您现在的位置是:首页 >学无止境 >Spring IOC - FactoryBean源码解析网站首页学无止境

Spring IOC - FactoryBean源码解析

zhangweiocp 2024-07-21 06:01:03
简介Spring IOC - FactoryBean源码解析

​​​​​1. 介绍

        FactoryBean是Spring框架中的一个接口,它允许我们自定义一个工厂类,用于创建和管理Spring容器中的Bean实例。FactoryBean接口定义了两个方法:

  • getObject():用于返回一个Bean实例,这个方法可以自定义创建Bean实例的逻辑。
  • getObjectType():用于返回创建的Bean实例的类型。

        当我们在Spring中自定义一个FactoryBean时,Spring容器会先创建这个FactoryBean实例,然后调用它的getObject()方法来获取实际的Bean实例。FactoryBean的使用场景比较广泛,例如:

  • 当我们需要创建一个Bean实例时,但是这个Bean实例的创建过程比较复杂,需要进行一些额外的逻辑处理,这时我们可以使用FactoryBean来自定义创建过程。
  • 当我们需要创建多个实例时,但是这些实例的创建逻辑比较相似,只有一些参数不同,这时我们可以使用FactoryBean来封装这些相似的逻辑,避免重复代码。

2. Demo

@Component
public class MyFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

public class FactoryBeanTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(FactoryBeanTest.class.getPackage().getName());
        System.out.println(annotationConfigApplicationContext.getBean("&myFactoryBean"));
        System.out.println(annotationConfigApplicationContext.getBean("myFactoryBean"));
    }
}

        返回结果如下: 

 3. 现象

  • FactoryBean会创建两个对象
  • beanName为myFactoryBean,实例为自己本身,存储在单例池singletonObjects(一级缓存)中

  • 通过getObject创建的对象,beanName为myFactory,缓存在factoryBeanObjectCache中,它是专门用来缓存通过FactoryBean创建的单例对象的。

  • 上述两个单例池均为ConcurrentHashMap类型,属于Spring容器的一部分。

  • 单例池和factoryBeanObjectCache中的beanName都为myFactory,没有&前缀,该前缀只是决定了从哪个缓冲池取对象

4. 源码解析

注:源码较长,只关注主干逻辑,省略了非主要代码

执行路径:main#getBean -》 AbstractApplicationContext#getBean -》 AbstractBeanFactory#doGetBean -》 AbstracBeanFactory#getObjectForBeanInstance -》 FactoryBeanRegistrySupport#getObjectFromFactoryBean -》FactoryBeanRegistrySupport#doGetObjectFromFactoryBean -》 FactoryBean#getObject

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   // 如果name以一个或多个&符合开头,则去掉该一个或多个&符号,否则直接返回
   // 如果是别名,则转换成规范名称
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   // 从单例池中获取实例,在AnnotationConfigApplicationContext实例化后,此时
   // 单例池中已有键值对:myFactoryBean:MyFactoryBean实例,所以能够获取到
   Object sharedInstance = getSingleton(beanName);
   // 接下来代码基本就是一个if-else分支
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 获取给定bean实例的对象,可以是bean实例本身,也可以是FactoryBean创建的对象
      // 下面会解析该方法
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   } else {
       // else分支在这里可以不用关注
   }
   return (T) bean;
}
protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

   // 如果bean实例是FactoryBean类型或者以&字符开头直接返回
   if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
      return beanInstance;
   }

   Object object = null;
   if (mbd == null) {
      // 从factoryBeanObjectCache缓冲池中获取对象
      object = getCachedObjectForFactoryBean(beanName);
   }
   if (object == null) {
      // Return bean instance from factory.
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // Caches object obtained from FactoryBean if it is a singleton.
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      // 非主逻辑代码,先忽略
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      // 通过回调FactoryBean#getObject获取对象,该方法继续调用doGetObjectFromFactoryBean
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
      throws BeanCreationException {

   Object object;
   try {
         // 回到factoryBean的getObject方法,返回的对象会缓存到factoryBeanObjectCache池子中
         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) {
      if (isSingletonCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(
               beanName, "FactoryBean which is currently in creation returned null from getObject");
      }
      object = new NullBean();
   }
   return object;
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。