Spring源码分析(六)FactoryBean 接口解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 说道FactoryBean,不少人会拿它跟BeanFactory作比较,但是实际上他们没有多大关系;我们简单介绍一下两者Part1一、BeanFactory和FactoryBean区别1BeanFactoryBeanFactory:这就是一个Factory,是一个IOC容器或者叫对象工厂,它里面存着很多的bean。例如默认的实现方式DefaultListableBeanFactory;我们把IOC容器可以比作一个水桶,IOC容器里面的所有bean就是装的水; ##FactoryBean

作者石臻臻, CSDN博客之星Top5Kafka Contributornacos Contributor华为云 MVP ,腾讯云TVP, 滴滴Kafka技术专家KnowStreaming, 《Kafka运维与实战宝典》电子书作者。 领取《Kafka运维与实战宝典》PDF请联系石臻臻


KnowStreaming  是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源!


说道FactoryBean,不少人会拿它跟BeanFactory作比较,但是实际上他们没有多大关系;我们简单介绍一下两者

Part1一、BeanFactory和FactoryBean区别

1BeanFactory


BeanFactory:这就是一个Factory,是一个IOC容器或者叫对象工厂,它里面存着很多的bean。例如默认的实现方式DefaultListableBeanFactory;我们把IOC容器可以比作一个水桶,IOC容器里面的所有bean就是装的水; ##FactoryBean


FactoryBean:是一个Java Bean,但是它是一个能生产对象的工厂Bean,把IOC容器比作水桶,那么Java Bean就是水桶里面的水,但是这个FactoryBean一种比较特殊的水,可以把它看成是一个水球,这个水球里面也包含了水,我们可以通过IOC取这个水球,但是也可以直接取水球里面的水;(用法就是  用&表示取水球,取水球里的水用正常的获取方式就行了;如果我们用&获取到了水球之后,可以通过这个水球的 getObject方法获取水球里面的水;)

在之前的文章中我们已经分析过BeanFactory的源码了,今天我们单独分析FactoryBean

2代码入口


public static void main(String[] args){
         ClassPathResource resource = new ClassPathResource("SpringContextConfig.xml");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);
        MyFactoryBean beanA = (MyFactoryBean)factory.getBean("&fb");
        TestFb beanB = (TestFb)factory.getBean("fb");
        TestFb beanC =beanA.getObject();
        System.out.print(beanB==beanC);
        System.out.print(beanA);
    }

3AbstractBeanFactory

AbstractBeanFactory extends FactoryBeanRegistrySupport

断点进去最后访问到AbstractBeanFactory的getObjectForBeanInstance方法;方法中的几个参数分别表示 beanInstance:通过Object sharedInstance = getSingleton(beanName);获取到的,这个就是实例化的对象,就算用我们getBean的时候beanName传的是fb,不是&fb,这里返回的就是FactoryBean的实例对象;就是上面比喻的水球; name:就是传进来的name   ;没有过滤&字符的; beanName:过滤了&字符的

/**专门缓存从FactoryBeans中生成的对象的;除了第一次要getObject(),后面直接从这个mao中取就行了 
 Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
 private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<String, Object>(16);
protected Object getObjectForBeanInstance(
   Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
  // 如果name 是&开头的,但是beanInstance又不是FactoryBean类型的就抛出异常
  if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
   throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
  }
  //如果不是FactoryBean 例如name=fb;直接返回
  //如果name是&开头并且FactoryBean类型的例如name=&fb,fb也是FactoryBean类型; 直接返回
  if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
   return beanInstance;
  }
 // beanInstance是FactoryBean类型的并且name不是是以&开头的;例如name=fb 就要走下面的流程
 //beanInstance不是FactoryBean类型并且name
  Object object = null;
  if (mbd == null) {
  //检查之前是否已经生成放入缓存了,如果有 直接返回
   object = getCachedObjectForFactoryBean(beanName);
  }
  if (object == null) {
   // Return bean instance from factory.
   FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
   // 获取合并之后的BeanDefinition
   if (mbd == null && containsBeanDefinition(beanName)) {
    mbd = getMergedLocalBeanDefinition(beanName);
   }
   //TODO....暂时不知道这里是怎么设置的,回头分析
   boolean synthetic = (mbd != null && mbd.isSynthetic());
   /**
   *1.返回FactoryBean.getObject()对象
   *2.执行后置处理器接口的方法BeanPostProcessor中的
   *postProcessAfterInitialization(result, beanName);方法;
   */
   object = getObjectFromFactoryBean(factory, beanName, !synthetic);
  }
  return object;
 }




4FactoryBeanRegistrySupport

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry{
 /**
  * 从FactoryBean中获取Bean
  * @param factory the FactoryBean instance
  * @param beanName the name of the bean
  * @param shouldPostProcess whether the bean is subject to post-processing
  * @return the object obtained from the FactoryBean
  * @throws BeanCreationException if FactoryBean object creation failed
  * @see org.springframework.beans.factory.FactoryBean#getObject()
  */
 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
 //判断factory是单例的并且beanName已经被创建
  if (factory.isSingleton() && containsSingleton(beanName)) {
   synchronized (getSingletonMutex()) {
   //如果已经创建过直接返回
    Object object = this.factoryBeanObjectCache.get(beanName);
    if (object == null) {
     object = doGetObjectFromFactoryBean(factory, beanName);
     // Only post-process and store if not put there already during getObject() call above
     // (e.g. because of circular reference processing triggered by custom getBean calls)
     //TODO....这里回头分析...
     Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
     if (alreadyThere != null) {
      object = alreadyThere;
     }
     else {
      if (object != null && shouldPostProcess) {
       try {
       //执行所有后置处理器接口的方法BeanPostProcessor中的postProcessAfterInitialization(result, beanName);方法;
       //这里单独写一篇文章将后置处理器BeanPostProcessor
        object = postProcessObjectFromFactoryBean(object, beanName);
       }
       catch (Throwable ex) {
        throw new BeanCreationException(beanName,
          "Post-processing of FactoryBean's singleton object failed", ex);
       }
      }
 //将通过factoryBean.getObject方法得到的对象存到 factoryBeanObjectCache中   this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
     }
    }
    return (object != NULL_OBJECT ? object : null);
   }
  }
  else {//如果不是单例对象
  //调用FactoryBean的getObject方法返回实例,也就是从水球里面取出水;
   Object object = doGetObjectFromFactoryBean(factory, beanName);
   if (object != null && shouldPostProcess) {
    try {
    //执行后置处理器
     object = postProcessObjectFromFactoryBean(object, beanName);
    }
    catch (Throwable ex) {
     throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
    }
   }
   return object;
  }
 }
 //调用FactoryBean的getObject放法
 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
   throws BeanCreationException {
  Object object;
  try {
   if (System.getSecurityManager() != null) {
    AccessControlContext acc = getAccessControlContext();
    try {
     object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
      @Override
      public Object run() throws Exception {
        return factory.getObject();
       }
      }, acc);
    }
    catch (PrivilegedActionException pae) {
     throw pae.getException();
    }
   }
   else {
    //可以看到最终调用了getObject方法;这是需要实现类自己实现
    object = factory.getObject();
   }
  }
  catch (FactoryBeanNotInitializedException ex) {
   throw new BeanCurrentlyInCreationException(beanName, ex.toString());
  }
  catch (Throwable ex) {
   throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
  }
  // Do not accept a null value for a FactoryBean that's not fully
  // initialized yet: Many FactoryBeans just return null then.
  if (object == null && isSingletonCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(
     beanName, "FactoryBean which is currently in creation returned null from getObject");
  }
  return object;
 }

Part2二、总结

总结一下整个FactoryBean源码的流程 1.判断是否需要调用FactoryBean的getObject方法来获取实例 判断依据是:①.如果name有前缀&,直接返回 ②.如果没有前缀&,调用getObject方法获取实例 2.如果是通过调用GetObject方法获取实例,则还要执行一下后置处理器 执行后置处理器接口的方法BeanPostProcessor中的 postProcessAfterInitialization(result, beanName);方法;

Part3三、分析过程有一些需要单独分析,占个坑


51. mbd.isSynthetic()中的值是什么时候设置的?有什么用?

TODO...

62.BeanPostProcessor后置处理器讲解

BeanPostProcessor解析

73.上面Object alreadyThere = this.factoryBeanObjectCache.get(beanName);这段代码的意思?什么情况下要先查这个?

TODO.....

说明文字

在这里插入图片描述

相关文章
|
7天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
22 2
|
7天前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
25 1
|
25天前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
19天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
39 3
|
22天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
31 1
|
28天前
|
存储 安全 Java
|
23天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
25 1
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
111 5
|
1月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
20天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
21 0

推荐镜像

更多