乐趣区

关于java:Spring源码之Bean的加载一

bean 的加载

之前文章次要剖析了对 XML 配置文件的解析,接下来就是对 bean 的加载进行剖析,同样开始用最开始的代码为入口。

入口代码 getBean

public void testSimpleLoad(){final BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
   final MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");
   assertEquals("testStr",myTestBean.getTestStr());
}

从这里咱们疾速先大抵理解一下是如何实现的。

从 BeanFactory 接口中咱们抉择对应实现类为 AbstractBeanFactory。

Object getBean(String name) throws BeansException;
@Override
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        // 通过三种模式获取 beanName, 一个是原始的 beanName,一个是加了 & 的,一个是别名
        // 返回容器中真是的 beanName
        final String beanName = transformedBeanName(name);
        Object bean;

        /**
         * 查看缓存中或实例工厂中是否存在对应实例
         * 因为在创立单例 bean 的时候会存在依赖注入的状况,Spring 为了防止循环依赖, 创立 bean 的准则是不等 bean 创立实现就会创立 bean 的 ObjectFactory 提前曝光
         * 也就是将 ObjectFactory 放入到了缓存中, 一旦下个 bean 创立时候须要依赖上一个 bean 则间接应用 ObjectFactory
         */
        // Eagerly check singleton cache for manually registered singletons.
        // 尝试从缓存中获取或者从 singleFactories 中的 ObjectFactory 中获取
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {
                // 如果 Bean 还在创立中,则阐明是循环援用
                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,间接返回,如果是 FactoryBean,则返回它的 getObject
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // 只有在单例状况下 Spring 才会尝试解决循环依赖, 在原型模式下如果存在 A ->B->A 的话就会抛出异样
            if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);
            }
            // 查看工厂中是否存在 bean 定义
            BeanFactory parentBeanFactory = getParentBeanFactory();
            // 如果 beanDefinitionMap 中不包含以后 beanName 则会尝试从 parentBeanFactory 中检测
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // 次要针对 FactoryBean,将 Bean 的 & 从新加上
                // 将转换过后的 BeanName 复原回原先的样子
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    // 递归到 BeanFactory 中寻找
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // 如果有参数,则委派父类容器依据指定名称和参数查找
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    // 委派父级容器依据指定名称和类型查找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    // 委派父级容器依据指定名称查找
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }
            // 如果不是仅仅做类型查看则是创立 bean, 进行记录
            if (!typeCheckOnly) {markBeanAsCreated(beanName);
            }

            try {
                // 将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition, 如果指定的 BeanName 是子 bean 的话还会合并父类的雷同属性
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // 对合并的 BeanDefinition 做验证,次要看属性是否为 abstract 的
                checkMergedBeanDefinition(mbd, beanName, args);

                String[] dependsOn = mbd.getDependsOn();
                // 如果存在依赖则须要递归实例化依赖的 bean
                if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between'" + beanName + "'and'" + dep + "'");
                        }
                        // 缓存依赖调用
                        registerDependentBean(dep, beanName);
                        try {
                            // 递归调用 getBean 办法,注册 Bean 之间的依赖(如 C 须要晚于 B 初始化,而 B 须要晚于 A 初始化)// 初始化依赖的 bean
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'"+ beanName +"' depends on missing bean '"+ dep +"'", ex);
                        }
                    }
                }
                // 实例化依赖的 bean 后就能够实例化 mbd 自身了
                // 如果 BeanDefinition 为单例
                if (mbd.isSingleton()) {
                    // 创立 Bean 实例对象,并且注册给所依赖的对象
                    sharedInstance = getSingleton(beanName, () -> {
                        try {return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // 从单例缓存中删除 bean 实例
                            // 因为单例模式下为了解决循环依赖,可能它曾经存在了,所以将其销毁
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    // 如果是一般 bean,间接返回,如果是 FactoryBean,则返回它的 getObject
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                // 如果 BeanDefinition 为 prototype
                else if (mbd.isPrototype()) {
                    // 每次创立一个新的对象
                    Object prototypeInstance = null;
                    try {
                        // 注册以后创立的 prototype 对象为正在创立中
                        beforePrototypeCreation(beanName);
                        // 创立原型对象实例
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        // 将先前注册的正在创立中的 Bean 信息给抹除掉
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
                // 如果不是原型模式和单例模式则可能是: request、session、application 等生命周期
                else {String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    //Bean 定义资源中没有配置生命周期范畴,则 Bean 定义不非法
                    if (scope == null) {throw new IllegalStateException("No Scope registered for scope name'" + scopeName + "'");
                    }
                    try {// 如果 bean 的 scope 不是 singleton 和 prototype, 则调用 scope.get()来抉择适合的加载策略
                        Object scopedInstance = scope.get(beanName, () -> {
                            // 注册以后创立的 prototype 对象为正在创立中
                            beforePrototypeCreation(beanName);
                            try {
                                // 创立 bean
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                // 将先前注册的正在创立中的 Bean 信息给抹除掉
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope'" + scopeName + "'is not active for the current thread; consider" +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Check if required type matches the type of the actual bean instance.
        // 查看须要的类型是否合乎 bean 的理论类型
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {
                    logger.trace("Failed to convert bean'" + name + "'to required type'" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        // 返回 bean 实例
        return (T) bean;
}

能够看到该办法代码量很多,咱们先大略整顿一下流程:

1. 转换对应 beanName

转换对应 beanName 的意思就是,这里咱们传入的 beanName 可能是别名也可能是 FactoryBean,所以要进行解析。

包含:

  • 去除 FactoryBean 的修饰符,也就是如果 name=&jack,那么会去除 & 而使 name=jack
  • 取指定 alias 所示意的最终 beanName,如果别名 A 指向名称 B 的 bean,则返回 B 的 bean;如果别名 A 指向别名 B,别名 B 又指向别名 C 则返回 C 的 bean

2. 尝试从缓存中加载单例

单例就是在 Spring 的同一容器中只会被创立一次,后续获取则无需再次创立,间接从单例缓存中获取。但这里也是尝试加载 bean,首先尝试从缓存中加载,如果加载不胜利则尝试从 singletonFactories 中加载 因为在创立单例 bean 的时候可能会存在依赖注入的状况,Spring 在创立依赖的时候为了防止循环依赖,创立 bean 的准则是不等 bean 创立实现就会将创立 bean 的 ObjectFactory 提前曝光退出到缓存中,一旦下一个 bean 创立时候须要依赖上一个 bean 则间接应用 ObjectFactory

3.bean 的实例化

如果从缓存中失去的是未实例化的 bean,则须要进行实例化操作,须要留神:缓存中记录的是最原始的 bean 状态,不肯定是咱们想要 bean。咱们须要的是工厂 bean 中定义的 factory-method 办法中返回的 bean,而 getObjectForBeanInstance 办法就是实现这个工作的。

4. 原型模式的依赖查看

只有单例的状况下才会尝试解决循环依赖,如果存在 A 中有 B 属性,B 中有 A 属性,当依赖注入时候就会产生 A 还没创立完的时候因为对于 B 的创立再次返回创立 A,造成循环依赖。也就是isPrototypeCurrentlyInCreation(beanName) 为 true。

5. 检测 parentBeanFactory

BeanFactory parentBeanFactory = getParentBeanFactory();

如果从缓存中没有获取到,就从父类工厂中去加载。

下一行去进行判断,如果 parentBeanFactory 为空一切都是浮云,随后去检测如果以后加载的 XML 配置中不蕴含 beanName 所对应的配置,就只能到 parentBeanFactory 中尝试,而后再去递归调用 getBean 办法。

if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {

6. 将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition

之前说过从 XML 中读取到的 bean 信息是存在 GenericBeanDefinition 中的,然而后续的 bean 解决都是针对 RootBeanDefinition 的,所以要进行一个转换,同时判断父类 bean 不为空的话,一并合并父类属性。

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

7. 寻找依赖

在 bean 初始化中可能会用到某些属性,而某些属性可能是动静配置的,并且依赖其余 bean,这时候须要先加载所依赖的 bean。

8. 针对不同 scope 进行 bean 的创立

该阶段对不同的 scope 进行 bean 的创立,默认的是 singleton,还有 prototype、request 等。

9. 类型转换

到这里基本上 bean 的创立就曾经完结了,这一步对 bean 进行一个转换,判断 requiredType != null 的话就转换为理论的类型。通过这些步骤后 bean 的创立就实现了,随后返回咱们须要的 bean。

总结

  1. 通过 getSingleton(beanName) 办法查看缓存中是否存在曾经加载的 bean
  2. 如果条件成立 if (sharedInstance != null && args == null),调用getObjectForBeanInstance(sharedInstance, name, beanName, null) 办法获取到 bean 实例,但有时存在比方 BeanFactory 的状况并不是间接返回实例自身而是返回指定办法的实例,并跳转到第 6 步
  3. if (parentBeanFactory != null && !containsBeanDefinition(beanName))如果以后不存在 beanName,调用办法 parentBeanFactory.getBean 去父类工厂中去找,父类工厂通常为空
  4. getMergedLocalBeanDefinition(beanName)将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition,如果指定 beanName 是子 Bean 的话同时合并父类相干属性 Text
  5. if (mbd.isSingleton()) else if (mbd.isPrototype())依据属性 bean 的属性 scope 进行不同的实例化
  6. if (requiredType != null && !requiredType.isInstance(bean))通过指定需要类型不为空进行类型转换,否则进行强制转换

理解了创立 bean 的整个过程,其中最重要的就是步骤 8,针对不同的 scope 进行创立。在细化各个步骤提供的性能前,咱们先理解一下 FactoryBean 的用法。

FactoryBean 的应用

Spring 通过反射机制来利用 bean 的 class 属性指定实现类来实例化 bean。在某些状况下,实例 bean 比较复杂,如果在 <bean> 标签中须要大量的配置信息并且灵活性受限。

Spring 中提供了 org.springframework.beans.factory.FactoryBean 的工厂接口,咱们能够实现这个接口来定制实例化 bean 的逻辑。

public interface FactoryBean<T> {

   String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

     /**
     * 返回由 FactoryBean 创立的 bean 实例, 如果 isSingleton()返回 true, 则该实例会放入到 Spring 容器的单例缓存池中
     */
   @Nullable
   T getObject() throws Exception;

  /**
     * 返回 FactoryBean 创立的 bean 类型
     */
   @Nullable
   Class<?> getObjectType();

  /**
     * 返回 FactoryBean 创立的 bean 实例的作用域是 singleton 还是 prototype
     */
   default boolean isSingleton() {return true;}

}

当配置文件中 <bean> 的 class 属性配置的实现类为 FactoryBean 时,通过 getBean() 办法获取返回到的不是 FactoryBean 自身,而是 FactoryBean#getObject()办法所返回的对象,相当于是代理了 getBean()办法。

如果应用传统形式配置上面 Car 的 <bean> 时,每一个属性则别离对应一个 <property> 标签。

/**
 * @author 神秘杰克
 * 公众号: Java 菜鸟程序员
 * @date 2022/5/30
 */
public class Car {

   private int maxSpeed;
   private String brand;
   private double price;
   // 省略 get / set
}

如果用 FactoryBean 的形式的话则会更加灵便一点,比方通过逗号宰割符的形式一次性为 Car 所有属性赋值。

/**
 * @author 神秘杰克
 * 公众号: Java 菜鸟程序员
 * @date 2022/5/30
 */
public class CarFactoryBean implements FactoryBean<Car> {

   private String carInfo;

   @Override
   public Car getObject() throws Exception {Car car = new Car();
      final String[] infos = carInfo.split(",");
      car.setBrand(infos[0]);
      car.setMaxSpeed(Integer.parseInt(infos[1]));
      car.setPrice(Double.parseDouble(infos[2]));
      return car;
   }

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

   public String getCarInfo() {return carInfo;}

   public void setCarInfo(String carInfo) {this.carInfo = carInfo;}

   @Override
   public boolean isSingleton() {return false;}

}

有了 CarFactoryBean 后,就能够在配置文件中应用上面这种自定义配置形式配置 Car Bean 了:

<bean id="car" class="cn.jack.CarFactoryBean">
   <property name="carInfo" value="宝马,400,20000000"/>
</bean>

当调用 getBean("car") 时,通过反射机制发现了 CarFactoryBean 实现了 FactoryBean 接口,这时候 Spring 容器就调用接口办法 CarFactoryBean#getObject()办法返回。如果要获取 CarFactoryBean 的实例,则须要在 beanName 后面应用“&”作为前缀,比方:getBean("&car")

缓存中获取单例 bean

理解 FactoryBean 的用法后,咱们就能够理解 bean 加载的过程了。

咱们晓得单例在 Spring 的同一个容器内只会被创立一次,后续再获取 bean 间接从单例缓存中获取,留神这里也只是 尝试加载

首先尝试从缓存中加载,而后再次尝试从 singletonFactories 中加载。因为在创立单例 bean 时会存在依赖注入的状况,而在创立依赖的时候为了防止循环依赖,Spring 创立 bean 的准则就是不等 bean 创立实现就会将 bean 的 ObjectFactory 提前曝光退出到缓存中,一旦下一个 bean 创立时须要依赖上个 bean,则间接应用 ObjectFactory。

public Object getSingleton(String beanName) {
   // 参数 true 示意容许晚期依赖
   return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 查看缓存中是否存在实例
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      // 为空则加锁
      synchronized (this.singletonObjects) {
         // 如果此时 bean 正在加载则不解决
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            // 当某些办法须要提前初始化时候则调用 addSingleTonFactory 办法讲对应的 ObjectFactory 初始化策略存入 singletonFactories
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               // 调用事后设定的 getObject 办法
               singletonObject = singletonFactory.getObject();
               // 记录到缓存中, 留神:earlySingletonObjects 和 singletonFactories 是互斥的
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

这个办法首先尝试从 singletonObjects 中获取实例,如果获取不到就从 earlySingletonObjects 中获取,如果还是获取不到则从 singletonFactories 外面获取 beanName 对应的 ObjectFactory,而后调用 ObjectFactory 的 getObject 来创立 bean,并放到 earlySingletonObjects 中,并且从 singletonFactories 中 remove 掉这个 ObjectFactory,后续所有内存操作都只为了循环依赖检测时候应用,也就是在 allowEarlyReference 为 true 的状况下应用。

总结

这外面提到用来存储 bean 的不同的 map:

  • singletonObjects一级缓存,保留 BeanName 和创立 bean 实例之间的关系,bean name –> bean instance
  • earlySingletonObjects二级缓存,保留 BeanName 和创立 bean 实例之间的关系,与 singletonObjects 不同的是,当一个单例 bean 放入这里后,那么当 bean 还在创立过程中时,就能够通过 getBean 办法获取到了,目标是用来检测循环援用
  • singletonFactories三级缓存,保留 BeanName 和创立 bean 的工厂之间的关系,bean name –> ObjectFactory
  • registeredSingletons:该实例是一个 Set 对象,用来保留以后所有曾经注册的 bean
退出移动版