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;
@Overridepublic 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。
总结
- 通过
getSingleton(beanName)
办法查看缓存中是否存在曾经加载的 bean - 如果条件成立
if (sharedInstance != null && args == null)
,调用getObjectForBeanInstance(sharedInstance, name, beanName, null)
办法获取到 bean 实例,但有时存在比方 BeanFactory 的状况并不是间接返回实例自身而是返回指定办法的实例,并跳转到第 6 步 if (parentBeanFactory != null && !containsBeanDefinition(beanName))
如果以后不存在 beanName,调用办法 parentBeanFactory.getBean 去父类工厂中去找,父类工厂通常为空getMergedLocalBeanDefinition(beanName)
将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition,如果指定 beanName 是子 Bean 的话同时合并父类相干属性 Textif (mbd.isSingleton()) else if (mbd.isPrototype())
依据属性 bean 的属性 scope 进行不同的实例化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 instanceearlySingletonObjects
:二级缓存,保留 BeanName 和创立 bean 实例之间的关系,与 singletonObjects 不同的是,当一个单例 bean 放入这里后,那么当 bean 还在创立过程中时,就能够通过 getBean 办法获取到了,目标是用来检测循环援用singletonFactories
:三级缓存,保留 BeanName 和创立 bean 的工厂之间的关系,bean name --> ObjectFactoryregisteredSingletons
:该实例是一个 Set 对象,用来保留以后所有曾经注册的 bean