本文已收录 【修炼内功】跃迁之路
书接上文,在 BeanDefinitionReader 一文中简单介绍了 XMLBeanFactory解析xml配置、并注册 BeanDefinition的逻辑,本文就bean的实例化过程及销毁作简要分析
先放一张大图(点击图片放大查看,右键或长按保存后更清晰),展现完整的bean建立过程及销毁过程,若是对spring原理有一些理解可将此图做为开发过程当中的参考,若是对spring原理还有一些模糊可继续向下阅读(长文预警!)java
经过前文简单了解到,Spring在初始化过程当中并非直接实例化bean,而是先收集全部bean的元数据信息并注册,bean的元数据描述为接口BeanDefinition
,该接口定义了你能想到的一切有关bean的属性信息web
BeanDefinition衍生出一系列实现类spring
如同其余Spring类,大部分BeanDefinition接口的逻辑都由该抽象类实现sql
GenericBeanDefinition是一站式、用户可见的bean definition,如何理解“用户可见”?数据库
可见的bean definition意味着能够在该bean definition上定义post-processor来对bean进行操做segmentfault
当bean definition存在父子关系的时候,RootBeanDefinition用来承载父元数据的角色(也可独立存在),同时它也做为一个可合并的bean definition使用,在Spring初始化阶段,全部的bean definition均会被(向父级)合并为RootBeanDefinition,子bean definition(GenericBeanDefinition/ChildBeanDefinition)中的定义会覆盖其父bean definition(由parentName指定)的定义缓存
当bean definition存在父子关系的时候,ChildBeanDefinition用来承载子元数据的角色(也可独立存在),在Spring推出GenericBeanDefinition后,其彻底能够被GenericBeanDefinition替代,目前使用场景已经很是少session
AnnotatedBeanDefinitionapp
如其名,主要用来定义注解场景的bean definition框架
主要用来定义@Component、@Service等bean definition,其AnnotationMetadata metadata属性用来存储该bean的类注解信息
与ScannedGenericBeanDefinition不一样的是,其主要用来定义@Configuration等配置类中@Bean的bean definition,其AnnotationMetadata metadata属性与ScannedGenericBeanDefinition相同,MethodMetadata factoryMethodMetadata属性用来存储@Bean描述的方法信息
BeanDefinitionHolder只是简单捆绑了BeanDefinition、bean-name、bean-alias,用于注册BeanDefinition及别名alias
在通常工程中,bean的定义分散在各类地方(尤为使用注解以后),Spring并不能在解析出每个bean的元数据信息后当即对该bean作实例化动做,对于依赖的分析与注入、类(方法)的代理、功能上的扩展等,必须等全部的bean元数据所有解析完成以后才能进行
在bean元数据解析完成以后、bean实例化以前,对bean的元数据信息有一个暂存的过程,这个过程即是bean的注册
bean的注册逻辑分两步,一为BeanDefinition的注册,一为别名的注册
在完成bean的元数据注册以后,即是根据详尽的元数据信息进行实例化了
bean的实例化过程比较复杂(Spring考虑到了各类场景),附上BeanRegistry&BeanFactory相关的类依赖图
初看此图,请不要失去信心和耐心,图中各种的做用会一一讲解(见 #附录#相关类说明),这里先介绍几个核心的接口
bean别名注册和管理
bean元数据注册和管理
单例bean注册和管理
bean工厂,提供各类bean的获取及判断方法
大体浏览上图(类依赖图)不难发现,核心实现落在了DefaultListableBeanFactory
,咱们以此类做为切入点分析bean实例化过程
bean的实例化过程发生在getBean
调用阶段(对于singleton则发生在首次调用阶段),getBean的实现方法众多,咱们追根溯源,找到最通用的方法AbstractBeanFactory#doGetBean
// org.springframework.beans.factory.support.AbstractBeanFactory protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 1. 获取真正的beanName final String beanName = transformedBeanName(name); Object bean; // 2. 尝试获取(提早曝光的)singleton bean实例(为了解决循环依赖) Object sharedInstance = getSingleton(beanName); // 3. 若是存在 if (sharedInstance != null && args == null) { ... } // 4. 若是不存在 else { ... } // 5. 尝试类型转换 if (requiredType != null && !requiredType.isInstance(bean)) { ... } return (T) bean; }
bean的实例化过程虽然复杂,但大致逻辑很是清楚
接下,就以上五个子流程(蓝色部分)一一展开
在实例化bean的过程中,Spring会使用大量的中间态来判断、处理各类场景和状况,此处先行列出Spring所使用的一些关键的中间态(各中间态的做用会在下文介绍,见 #附录#中间态说明),以便在下文中更好地理解bean实例化过程当中对各类状况的判断和处理逻辑
在使用bean-name获取bean的时候,除了可使用原始bean-name以外,还可使用alias别名等,bean-name的转换则是将传入的‘bean-name’一层层转为最原始的bean-name
Return the bean name, stripping out the factory dereference prefix if necessary, and resolving aliases to canonical names.
protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); }
函数canonicalName的做用则是利用别名注册aliasMap,将别名alias转为原始bean-name
函数transformedBeanName比较特殊,其是将FactoryBean的bean-name前缀 '&' 去除(BeanFactory#FACTORY_BEAN_PREFIX 下文会介绍)
拿到原始的bean-name以后,即可以实例化bean或者直接获取已经实例化的singleton-bean,此处为何叫‘尝试’获取呢?
在获取singleton-bean的时候通常存在三种状况:1. 还未实例化(或者不是单例);2. 已经实例化;3. 正在实例化;
Spring中对于singleton-bean,有一个sharedInstance的概念,在调用getSingleton
函数时,返回的不必定是彻底实例化的singleton-bean,有多是一个中间状态(建立完成,但未进行属性依赖注入及其余后处理逻辑),这种中间状态会经过getSingleton函数提早曝光出来,目的是为了解决循环依赖(下文会详细介绍循环依赖)
在实例化 beanA的过程当中,须要依赖 beanB和 beanC,若是 beanC同时又依赖 beanA,则须要 beanA在实例化完成以前提早曝光出来,以避免形成 beanA等待 beanC实例化完成, beanC等待 beanA实例化完成,相似一种死锁的状态
在继续进行以前,有必要简单介绍几个中间态(详见 #附录#中间态说明)
缓存已经实例化完成的singleton-bean
缓存正在实例化的、提早曝光的singleton-bean,用于处理循环依赖
缓存用于生成earlySingletonObject的 ObjectFactory
ObjectFactory,定义了一个用于建立、生成对象实例的工厂方法
@FunctionalInterface public interface ObjectFactory<T> { T getObject() throws BeansException; }
介绍了上述以后,再来描述getSingleton
的逻辑就会比较清楚
不用纠结上述中间态的值是什么时候被设置进去的,下文会逐步说起
上述 sharedInstance 必定是咱们须要的bean实例么?未必!
定义bean的时候能够经过实现FactoryBean接口来定制bean实例化的逻辑,以此增长更多的灵活性及可能性(How to use the Spring FactoryBean?)
@Bean(initMethod = "init", destroyMethod = "destroy") public FactoryBean myBean() { return new FactoryBean<MyBean>() { /** * 定制bean初始化逻辑 */ @Override public MyBean getObject() throws Exception { MyBean myBean = new MyBean(); // ... 定制化的逻辑 return myBean; } /** * 真正的bean类型 */ @Override public Class<?> getObjectType() { return MyBean.class; } @Override public boolean isSingleton() { return true; } } }
经过注册FactoryBean类型的bean,实例化后的原始实例类型一样为FactoryBean,但咱们须要的是经过FactoryBean#getObject方法获得的实例,这便须要针对FactoryBean作一些处理,这也是接下来要讲解的函数AbstractBeanFactory#getObjectForBeanInstance
Get the object for the given bean instance, either the bean instance itself or its created object in case of a FactoryBean.Now we have the bean instance, which may be a normal bean or a FactoryBean.
If it's a FactoryBean, we use it to create a bean instance.
该函数要实现的逻辑比较简单,若是sharedInstance是 FactoryBean,则使用getObject
方法建立真正的实例
getObjectForBeanInstance是一个通用函数,并不仅针对经过 getSingleton获得的 sharedInstance,任何经过缓存或者建立获得的 rawInstance,都须要通过 getObjectForBeanInstance处理,拿到真正须要的 beanInstance
简单介绍getObjectForBeanInstance函数的入参
/** * @param beanInstance sharedInstance / rawInstance,可能为FactoryBean * @param name 传入的未作转换的 bean name * @param beanName 对name作过转换后的原始 canonical bean name * @param mbd 合并后的RootBeanDefinition,下文会介绍 */ protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd)
getObjectForBeanInstance函数的处理逻辑
上图中有一个逻辑判断,若是入参name以'&' (BeanFactory#FACTORY_BEAN_PREFIX)开头则直接返回(BeanFactory)
这里兼容了一种状况,若是须要获取/注入FactoryBean而不是getObject生成的实例,则须要在bean-name/alias-name前加入'&'
/** * 注入FactoryBean#getObject生成的实例 */ @Autowired private MyBean myBean; /** * 直接注入FactoryBean */ @Resource(name = "&myBean") private FactoryBean<MyBean> myFactoryBean;
对于singleton,FactoryBean#getObject的结果会被缓存到factoryBeanObjectCache,对于缓存中不存在或者不是singleton的状况,会经过FactoryBean#getObject生成(上图中蓝色未展开的逻辑)
Spring并不是简单的调用FactoryBean#getObject,而是分为两部分处理
上图中doGetObjectFromFactoryBean,主要对getObject方法进行了包装,判断是否须要在SecurityManager框架内执行以及对null结果进行封装(NullBean)
上图中postProcessObjectFromFactoryBean,主要对生成的bean instance作一些后处理(能够跟踪到AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization),
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { // 拿到全部注册的BeanPostProcessor,执行后处理动做 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
postProcessAfterInitialization函数能够对现有bean instance作进一步的处理,甚至能够返回新的bean instance,这就为bean的加强提供了一个很是方便的扩展方式(能够思考一下,AOP的代理类是如何生成的)
以上,讨论了bean instance存在于缓存中的状况,若是缓存中不存则须要进行bean的加载
简单来说,bean的加载/建立分为三大部分
这里相似类继承,子BeanDefinition属性会覆盖父BeanDefinition
对于有依赖的状况,优先递归加载依赖的bean
将BeanDefinition转为RootBeanDefinition,若是存在父子关系,则进行合并
这里再也不赘述,能够参考 AbstractBeanFactory#getMergedLocalBeanDefinition
String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { // 遍历全部的依赖 for (String dep : dependsOn) { // 检测循环依赖 if (isDependent(beanName, dep)) { /* throw exception */ } // 注册依赖关系 registerDependentBean(dep, beanName); // 递归getBean,加载依赖bean try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { /* throw exception */ } } }
逻辑很简单,但这里涉及到两个中间态dependentBeanMap、dependenciesForBeanMap
存储哪些bean依赖了我(哪些bean里注入了我)
若是 beanB -> beanA, beanC -> beanA,key为beanA,value为[beanB, beanC]
存储我依赖了哪些bean(我注入了哪些bean)
若是 beanA -> beanB, beanA -> beanC,key为beanA,value为[beanB, beanC]
理解二者的存储关系,有助于在阅读源码的过程当中理解bean的加载和销毁顺序
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { // singletonFactory - ObjectFactory try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
这里涉及两个比较核心的函数createBean
、getObjectForBeanInstance
根据BeanDefinition的内容,建立/初始化bean instance
上文已经介绍过,主要处理FactoryBean,将FactoryBean转为真正须要的bean instance
createBean被包装在lambda(singletonFactory)中做为getSingleton的参数,咱们来看getSingleton的实现逻辑
<img src="../notes/BeanFactory/Flowchart.createSingleton.jpg" alt="Flowchart.createSingleton" style="zoom:50%;" />
因此,关键的逻辑在createBean函数中,bean的建立逻辑较为复杂,咱们放到后面介绍
else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); }
prototype bean的建立与singleton bean相似,只是不会缓存建立完成的bean
scope,即做用域,或者能够理解为生命周期
上文介绍了singleton-bean及prototype-bean的建立过程,严格意义上讲以上两种都是一种特殊的scope-bean,分别对应ConfigurableBeanFactory#SCOPE_SINGLETON及ConfigurableBeanFactory#SCOPE_PROTOTYPE,前者做用域为整个IOC容器,也可理解为单例,后者做用域为所注入的bean,每次注入(每次触发getBean)都会从新生成
Spring中还提供不少其余的scope,如WebApplicationContext#SCOPE_REQUEST或WebApplicationContext#SCOPE_SESSION,前者做用域为一次web request,后者做用域为一个web session周期
自定义scope的bean实例建立过程与singleton bean的建立过程十分类似,须要实现Scope的get方法(org.springframework.beans.factory.config.Scope#get),
else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { /* throw exception */ } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); // createBean被封装在Scope#get函数的lambda参数ObjectFactory中 try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { /* throw exception */} }
Scope接口除了get方法以外,还有一个remove方法,前者用于定义bean的初始化逻辑,后者用于定义bean的销毁逻辑
public interface Scope { /** * Return the object with the given name from the underlying scope */ Object get(String name, ObjectFactory<?> objectFactory); /** * Remove the object with the given name from the underlying scope. */ Object remove(String name); }
WebApplicationContext#SCOPE_SESSION对应的Scope实现见org.springframework.web.context.request.SessionScope
WebApplicationContext#SCOPE_REQUEST对应的Scope实现见org.springframework.web.context.request.RequestScope
以上两种Scope实现都较为简单,前者将初始化的bean存储在request attribute种,后者将初始化的bean存储在http session中,具体细节请自行查阅源码
Q: Spring中实现了哪些Scope?又是何时注册的?
AbstractAutowireCapableBeanFactory#createBean
了解bean建立的过程也是一个抽丝剥茧的过程,真正建立的过程封装在AbstractAutowireCapableBeanFactory#doCreateBean中,而在此以前有一些准备工做,总体流程以下图
这一步骤用于锁定bean class,在没有显示指定beanClass的状况下,使用className加载beanClass
在 [[spring-framework] [2] BeanDefinitionReader](https://segmentfault.com/a/11... 一文中有提到过lookup-method及replace-method,该步骤是为了确认以上两种配置中的method是否存在
执行InstantiationAwareBeanPostProcessor前处理器(postProcessBeforeInstantiation)
这里要特别注意的是,若是这个步骤中生成了“代理”bean instance,则会有一个短路操做,直接返回
该bean instance而再也不执行doCreate,这是一个“细思极恐”的操做,但在一些特殊场景(尤为框架之中)提供了良好的扩展机制
try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { // 若是这里生成了代理的bean instance会直接返回 return bean; } } cache (Throwable ex) { // throw exception } try { // 建立bean instance Object beanInstance = doCreateBean(beanName, mbdToUse, args); // ... }
Q: InstantiationAwareBeanPostProcessor的使用场景有哪些?Spring有哪些功能使用了InstantiationAwareBeanPostProcessor?它们是在何时注册的?
真正bean的建立及初始化过程在此处实现,但Spring对bean建立及初始化逻辑的复杂程度彻底超出了本篇文章之承载,这里只对一些关键的逻辑作梳理
AbstractAutowireCapableBeanFactory#createBeanInstance
从上面的流程图能够看出,建立bean实体不必定会使用到构造函数,有两个特殊的方式
AbstractAutowireCapableBeanFactory#obtainFromSupplier
从Spring5开始,多了一种以函数式注册bean的方式(参考https://www.baeldung.com/spri...)
// 注册MyService context.registerBean(MyService.class, () -> new MyService()); // 注册MyService,并指定bean name context.registerBean("mySecondService", MyService.class, () -> { MyService myService = new MyService(); // 其余的逻辑 return myService; }); // 注册MyService,指定bean name,并加强bean definition context.registerBean("myCallbackService", MyService.class, () -> { MyService myService = new MyService(); // 其余的逻辑 return myService; }), bd -> bd.setAutowireCandidate(false));
或者
// 构建BeanDefinition BeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MyService.class, () -> { MyService myService = new MyService(); // 其余的逻辑 return myService; }); // 注册BeanDefinition beanFactory.registerBeanDefinition("myService", bd);
经过以上方式注册的bean,Spring会调用该supplier生成bean实体
AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod
ConstructorResolver#instantiateUsingFactoryMethod
在xml配置中还有一种不太常见的bean注册方式
public class MyHome { // 静态方法 public static MyHome create() { return new MyHome(); } } public class MyFactory { // 非静态方法 public MyHome create() { return new MyHome(); } }
<bean id="myFactory" class="com.manerfan.MyFactory"></bean> <!-- 方式一 --> <!-- 使用指定类的静态方法 --> <bean id="myHome1" class="com.manerfan.MyHome" factory-method="create"></bean> <!-- 方式二 --> <!-- 使用指定bean的非静态方法 --> <bean id="myHome2" class="com.manerfan.MyHome" factory-method="create" factory-bean="myFactory"></bean>
Spring会经过指定类的指定方法生成bean实体,其中有两种方式,一种方式(仅指定factory-method)使用指定类的静态方法生成,另外一种方式(同时指定factory-method和factory-bean)使用指定bean的非静态方法生成
同时factory-method中还容许传入一些参数,若是存在同名函数,Spring会根据参数的个数及类型找到匹配的method
public class MyHome { private MyHouse house; private MyCar car; // setters } public class MyFactory { // 携带入参 public MyHome create(MyHouse house, MyCar car) { MyHome myHome = new MyHome(); myHome.setHouse(house); myHome.setCar(car) return myHome; } // 同名函数 public MyHome create(MyHouse house) { MyHome myHome = new MyHome(); myHome.setHouse(house); myHome.setCar(defaultCar) return myHome; } }
<bean id="myHome2" class="com.manerfan.MyHome" factory-method="create" factory-bean="myFactory"> <!-- 这里使用的是构造函数参数类型 --> <constructor-arg name="house" ref="house"/> <constructor-arg name="car" ref="car"/> </bean>
这样的代码是否是让你想到了@Configuration中的@Bean,@Bean所修饰方法若是存在参数的话,Spring会经过参数的类型及名称自动进行依赖注入
@Configuration public class MyFactory { @Bean public MyHome create(MyHouse house, MyCar car) { MyHome myHome = new MyHome(); myHome.setHouse(house); myHome.setCar(car) return myHome; } }
咱们能够大胆猜想,@Configuration + @Bean的实现方式就是factory-bean + factory-method,在后文介绍Spring的注解体系时会揭晓
使用指定(类)bean的(静态)方法建立bean实体的逻辑在ConstructorResolver#instantiate(String, RootBeanDefinition, Object, Method, args),而真正的逻辑在SimpleInstantiationStrategy#instantiate(RootBeanDefinition, String, BeanFactory, Object, Method, Object...),其核心的执行逻辑很是简单,有了方法factoryMethod(factoryBean)及入参args,即可以调用该方法建立bean实体
Object result = factoryMethod.invoke(factoryBean, args);
factoryBean能够经过beanFactory.getBean获取到(正是当前在讲的逻辑),factoryMethod能够经过反射获取到,入参args如何获取?这便涉及到Spring中的一个重要概念 -- 依赖注入,如何准确的找到依赖的实体并将其注入,即是接下来的重点,这里涉及到一个很是重要的函数ConstructorResolver#resolvePreparedArguments,该函数的做用是将BeanDefinition中定义的入参转换为真是须要的参数(xml中定义的或者注解中定义的),在 BeanDefinitionReader 一文中有过介绍,ref
会被封装为RuntimeBeanReference
存储、value
会被封装为TypedStringValue
存储等等,如何将这些封装好的存储类型转为真正须要的函数参数,即是ConstructorResolver#resolvePreparedArguments函数的做用
这里分红了三大分支
resolveValueIfNecessary
针对BeanMetadataElement,进行值的转换,其中又会包含特别细的分支,大体以下
AbstractBeanFactory#evaluateBeanDefinitionString
支持Spl表达式解析bean name
BeanDefinitionValueResolver#resolveInnerBean
与createBean函数的逻辑相似,建立一个inner bean
AutowireCapableBeanFactory#resolveDependency
用来处理OptionalBean、LazyBean、AutowireCandidateBean等(详见下文“注解注入”一节)
BeanDefinitionValueResolver#resolveManagedArray
BeanDefinitionValueResolver#resolveManagedList
BeanDefinitionValueResolver#resolveManagedSet
BeanDefinitionValueResolver#resolveManagedMap
内部递归使用resolveValueIfNecessary方法获取bean并最终封装成对应的类型
经过BeanDefinitionValueResolver#evaluate(Spel)计算value的值,最终封装为Properties
经过BeanDefinitionValueResolver#evaluate(Spel)计算value的值
对于这部份内容,Spring在接下来的发展中可能还会不断地扩充
AbstractBeanFactory#evaluateBeanDefinitionString
与resolveValueIfNecessary中的RuntimeBeanNameReference一致,支持Spl表达式解析表达式
其余
InjectionPoint
使用ThreadLocal提供当前bean被注入到的注入点,能够参考 https://www.baeldung.com/what...
@Bean @Scope("prototype") public Logger logger(InjectionPoint injectionPoint) { // return MyComponent.class return Logger.getLogger(injectionPoint.getMethodParameter().getContainingClass()); } @Component public class MyComponent { @Autowired private Logger logger; }
与resolveValueIfNecessary中的DependencyDescriptor一致,用来处理OptionalBean、LazyBean等
须要留意的是,上述在进行依赖注入的过程当中,都会调用 DefaultSingletonBeanRegistry#registerDependentBean方法,将各bean之间的依赖关系保存起来,如同前文在介绍加载depends-on时一致,bean之间的依赖关系会分别存放在 dependentBeanMap及 dependenciesForBeanMap之中(下文在介绍属性注入的时候亦是如此),这对于bean销毁顺序的理解起着相当重要的做用
在返回以前还有convertIfNecessary的方法调用,该函数是将上述解析获得的值转换为函数参数真正的类型
为什么要转换?其实上述过程拿到的值并不是真正须要的值,如
public class MyComponent { private Resource initSql; }
<bean id="myComponent" class="com.manerfan.MyComponent"> <property name="initSql" value="classpath:/init/sql/init.sql"></property> </bean>
或者
public class MyComponent { @Value("${init.sql}") // or @Value("classpath:/init/sql/init.sql") private Resource initSql; }
init.sql=classpath:/init/sql/init.sql
不论哪一种形式,在convertIfNecessary以前解析到的值都是字符串 "classpath:/init/sql/init.sql",convertIfNecessary的做用即是将上述解析获得的值转换为函数参数真正的类型Resource
convert的逻辑在TypeConverterDelegate#convertIfNecessary,其内部基本的逻辑为
将url转换为Resource的PropertyEditor对应为 org.springframework.core.io.ResourceEditor,正是使用ResourceEditor将 字符串"classpath:/init/sql/init.sql”转为对应的Resource
Q: Spring默认的PropertyEditor有哪些?又是何时注册的?
AbstractAutowireCapableBeanFactory#autowireConstructor
ConstructorResolver#autowireConstructor
使用有参构造函数建立bean实例的一个点在于寻找与参数相对应的构造函数(可能定义了多个构造函数),而对于参数的解析和转换(参数的依赖注入)则与使用factory method同样,调用ConstructorResolver#resolvePreparedArguments函数进行处理,这里再也不重复描述
在拿到真实的入参及对应的构造函数后,下一步即是使用构造函数来建立bean实例,但事情貌似也并无那么简单
实例化的过程在ConstructorResolver#instantiate,内部并无统一利用反射技术直接使用构造函数建立,而是分为两种状况
一种,没有设置override-method时,直接使用构造函数建立
一种,在设置了override-method时,使用cglib技术构造代理类,并代理override方法
以上,Spring默认的实例化策略为CglibSubclassingInstantiationStrategy
AbstractAutowireCapableBeanFactory#instantiateBean
无参构造函数建立bean实例的过程与有参构造函数建立过程彻底一致,只是少了参数的依赖注入,使用默认无参构造函数进行实例化
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
在属性注入以前提供一次机会来对BeanDefinition进行处理,内部执行全部注册MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
在阅读源码时注意到一个MergedBeanDefinitionPostProcessor的实现类 AutowiredAnnotationBeanPostProcessor,深刻到实现内部AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata,其实现了两个注解类的解析 @Value 及 @Autowired ,找到注解修饰的Filed或者Method并缓存,具体的逻辑会在属性注入一节中详细介绍
Q: Spring注册了哪些MergedBeanDefinitionPostProcessor?它们都是作什么用的?又是何时注册的?
DefaultSingletonBeanRegistry#addSingletonFactory -> AbstractAutowireCapableBeanFactory#getEarlyBeanReference
还记得上文介绍的“尝试获取单例”(AbstractBeanFactory.getSingleton)么?为了解决循环依赖会将singleton-bean提早暴露出来,暴露的逻辑会封装为ObjectFactory(AbstractAutowireCapableBeanFactory#getEarlyBeanReference实现)缓存在DefaultSingletonBeanRegistry.singletonFactories中,在getBean的逻辑getSingleton中会执行ObjectFactory的逻辑将singleton提早暴露
此时暴露的singleton-bean仅完成了bean的实例化,属性注入、初始化等逻辑均暂未执行
AbstractAutowireCapableBeanFactory#populateBean
在“建立bean实体”小节中介绍了factory method方式及有参构造函数方式的参数注入逻辑,除此以外还有一种注入即是属性注入
流程图中两次出现了InstantiationAwareBeanPostProcessor,还记得在“Bean建立过程”小结中介绍的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation么?若是该步骤生成了“代理”bean instance,则会有一个短路操做,直接返回
该bean instance而再也不执行后续的doCreate
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation一样是一个短路操做,若是有任意一个InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法返回false,则会跳出属性注入的逻辑,官方对此的解释以下
Give any InstantiationAwareBeanPostProcessors the opportunity to modify the state of the bean before properties are set. This can be used, for example, to support styles of field injection.
autowireByName及autowireByType方法做为“候补”补充BeanDefinition的propertyValues
Fill in any missing property values with references to other beans.
PropertyValue中记录了须要注入的属性信息及须要注入的属性值,那BeanDefinition的propertyValues都来自哪里?xml中的bean配置、自定义的BeanDefinition等
public class MyService { /** * string */ private String name; /** * resource */ private Resource res; /** * bean ref */ private MyComponent myComponent; }
xml中定义PropertyValue
<bean id="myMyService" class="com.manerfan.MyService"> <property name="name" value="SpringDemoApp"></property> <property name="res" value="classpath:/init/init.sql"></property> <property name="myComponent" ref="myComponent"></property> </bean>
BeanDefinition中直接定义PropertyValue
// 构建BeanDefinition BeanDefinition bd = BeanDefinitionBuilder .genericBeanDefinition(MyService.class) .addPropertyValue("name", "${spring.application.name}") .addPropertyValue("res", "classpath:/init/init.sql") .addPropertyReference("myComponent", "myComponent") .getBeanDefinition(); // 注册BeanDefinition beanFactory.registerBeanDefinition("myService", bd);
全部的ProperValue均会在AbstractAutowireCapableBeanFactory#applyPropertyValues中进行依赖的解析、转换并设置到bean实例对应的属性中,详细的逻辑下文介绍
除此以外经过注解修饰的属性(方法)是如何注入的?
public class MyService { /** * string */ @Value("${spring.application.name}") private String name; /** * resource */ @Value("classpath:/init/init.sql") private Resource res; /** * bean ref by parameter */ @Autowired @Qualifier("myComponent1") // or @Resource("myComponent1") // or @Inject private MyComponent myComponent1; private MyComponent myComponent2; /** * bean ref by setter method */ @Autowired public void setMyComponet2(@Qualifier("myComponent1") MyComponet component) { this.myComponent2 = component } }
各注解的使用能够参考 https://www.baeldung.com/spri...
在AbstractAutowireCapableBeanFactory#applyPropertyValues以前发现还有一个动做InstantiationAwareBeanPostProcessor#postProcessProperties(是的InstantiationAwareBeanPostProcessor又出现了),在此有两个实现引发了个人注意AutowiredAnnotationBeanPostProcessor#postProcessProperties及CommonAnnotationBeanPostProcessor#postProcessProperties,咱们来对比两个实现的内部逻辑
// AutowiredAnnotationBeanPostProcessor#postProcessProperties public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { /* handle exception */ } return pvs; }
// CommonAnnotationBeanPostProcessor#postProcessProperties public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { /* handle exception */ } return pvs; }
从代码及流程图能够看出,两种实现的差别仅在InjectionMetadata的查找逻辑,一个个来
AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata的核心逻辑能够追踪到AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
CommonAnnotationBeanPostProcessor#findResourceMetadata的核心逻辑能够追踪到CommonAnnotationBeanPostProcessor.buildResourceMetadata
以上,对于不一样的注解不一样的方式(属性/方法),会被封装为不一样的InjectionElement,并最终将全部的InjectionElement封装在InjectionMetadata中
在找到InjectionElement以后,下一步即是依赖的解析和注入了(InjectionMetadata#inject)
这里的逻辑无非就是遍历内部全部的InjectionElement并执行InjectionElement.inject,上面已经介绍,对于不一样的注解不一样的方式(属性/方法),会被封装为不一样的InjectionElement,那不一样的InjectionElement也会有不一样的inject逻辑,至此咱们大体能够理出一个注解注入的大框架
因此,归根结底,注入的过程在AutowiredFieldElement、AutowiredMethodElement、ResourceElement、等InjectionElement内部,在继续进行以前有必要了解一下DefaultListableBeanFactory#resolveDependency
还记得上文“建立bean实体”一节中介绍参数的注入时提到的AutowireCapableBeanFactory#resolveDependency么?该函数正是调用了DefaultListableBeanFactory#resolveDependency,上文并未详细展开该函数的逻辑实现,其除了处理OptionalBean、及LazyBean以外,咱们比较关心的逻辑在DefaultListableBeanFactory#doResolveDependency
该函数处理了@Value、@Qualifier、@Primary、@Order等的逻辑
@Value的解析有两个过程,1. StringValueResolver解析(${spring.sql.init} -> classpath:/init/init.sql);2. PropertyEditor转换(classpath:/init/init.sql -> Resouce);
AutowiredFieldElement无非就是使用DefaultListableBeanFactory#doResolveDependency将依赖的bean解析到,并设置到对应的属性上
AutowiredMethodElement则是使用DefaultListableBeanFactory#doResolveDependency将参数对应依赖的bean解析到,并执行对应的方法
Q: 咱们是否能够自定义注解( InstantiationAwareBeanPostProcessor),来实现相似 @Value、 @Autowired 的功能?
AbstractAutowireCapableBeanFactory#applyPropertyValues
还记得在一开始提到的BeanDefinition中的propertyValues么?(xml中的bean配置、自定义的BeanDefinition,也有可能来自InstantiationAwareBeanPostProcessor#postProcessProperties),至此这一部分的属性还未注入依赖
PropertyValue中记录了须要注入的属性,已经依赖的类型(String、RuntimeBeanReference、等),根据不一样的类型解析依赖的bean并设置到对应的属性上(此过程与DefaultListableBeanFactory#doResolveDependency极其类似,再也不赘述)
AbstractAutowireCapableBeanFactory#initializeBean
以上,完成了bean实例的建立和属性注入,以后还有一些初始化的方法,好比各类Aware的setXxx是如何调用的、@PostConstruct是怎么调用的?
Q: Aware类有不少,除了上图中的三种以外,其余的Aware是何时调用的?Q: @PreDestroy是如何调用的?destroy-method是什么时候执行的?
Q: AbstractAdvisingBeanPostProcessor都作了什么?是如何处理AOP代理的?
AbstractBeanFactory#registerDisposableBeanIfNecessary
至此,终于完成了bean实例的建立、属性注入以及以后的初始化,此后即可以开始使用了
在使用Spring的过程当中常常还会碰到设置销毁逻辑的状况,如数据库链接池、线程池等等,在Spring销毁bean的时候还须要作一些处理,相似于C++中的析构
在bean的建立逻辑中,最后一个步骤则是注册bean的销毁逻辑(DisposableBean)
销毁逻辑的注册有几个条件
if (!mbd.isPrototype() && requiresDestruction(bean, mbd))
知足以上条件的bean会被封装为DisposableBeanAdapter,并注册在DefaultSingletonBeanRegistry.disposableBeans中(详见附录#中间态说明)
Q: 理解了bean的销毁注册逻辑,那bean的销毁时什么时候触发以及如何执行的?
以上,完成了bean的建立、属性的注入、dispose逻辑的注册,但得到的bean类型与实际须要的类型可能依然不相符,在最终交付bean以前(getBean)还须要进行一次类型转换,上文反复提到过PropertyEditor,此处不例外,使用的既是PropertyEditor进行的类型转换,具体的逻辑再也不赘述,再将bean转换为真正须要的类型后,便完成了整个getBean的使命
了解了bean的完成建立过程后,那bean是如何销毁的呢?
bean的建立过程始于DefaultListableBeanFactory.getBean,销毁过程则终于ConfigurableApplicationContext#close,跟踪下去,具体的逻辑在DefaultSingletonBeanRegistry#destroySingletons
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry public void destroySingletons() { synchronized (this.singletonObjects) { this.singletonsCurrentlyInDestruction = true; } String[] disposableBeanNames; synchronized (this.disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); } for (int i = disposableBeanNames.length - 1; i >= 0; i--) { // 遍历注册的DisposableBean destroySingleton(disposableBeanNames[i]); } // 清理各类缓存 this.containedBeanMap.clear(); this.dependentBeanMap.clear(); this.dependenciesForBeanMap.clear(); clearSingletonCache(); }
在介绍bean建立的时候提到过两个概念
须要注册销毁逻辑的bean会被封装为DisposableBeanAdapter并缓存在此处
对于存在依赖注入关系的bean,会将bean的依赖关系缓存在此处(dependentBeanMap: 哪些bean依赖了我; dependenciesForBeanMap: 我依赖了哪些bean)
从上图中能够看出,bean的销毁顺序与建立顺序正好相反,若是有 beanA --dependsOn--> beanB --> beanC ,建立(getBean)时必定是beanC -> beanB -> beanA,销毁时必定是 beanA -> beanB -> beanC,以此避免由于依赖关系形成的一些异常状况
在介绍Bean建立的时候提到过earlySingletonObject,为了解决循环依赖的问题,在实例化完后属性注入以前会提早将当前的bean实体暴露出来,以防止在属性注入过程当中所注入的bean又依赖当前的bean形成的相似“死锁”的状态,但即使有这样的逻辑仍是要注意几点
@DependsOn("beanB") @Component public class BeanA {} @DependsOn("beanC") @Component public class BeanB {} @DependsOn("beanA") @Component public class BeanC {}
dependsOn的依赖,在bean的建立以前便会处理
Spring在实例化以上bean时,在建立BeanA以前会触发建立BeanB,建立BeanB以前会触发建立BeanC,而建立BeanC以前又会触发建立BeanA,由此引起一个无解的循环依赖
@Component public class BeanA { public BeanA(BeanB beanB) { } } @Component public class BeanB { public BeanB(BeanC beanC) { } } @Component public class BeanC { public BeanC(BeanA beanA) { } }
与dependsOn同样的原理,构造函数参数依赖,一样在bean的建立以前便会处理,从而引起无解的循环依赖
@Bean public BeanA beanA(BeanB beanB) { return new BeanA(); } @Bean public BeanB beanB(BeanC beanC) { return new BeanB(); } @Bean public BeanC beanC(BeanA beanA) { return new BeanC(); }
原理与上述相同,再也不赘述
@DependsOn("beanB") @Component public class BeanA { } @Component public class BeanB { public BeanB(BeanC beanC) { } } @Bean public BeanC beanC(BeanA beanA) { return new BeanC(); }
彷佛咱们找到了必定的规律,只要一个循环依赖中的全部bean,其依赖关系都须要在建立bean实例以前进行解决,此循环依赖则必定无解
还以上述三个Bean为例,先将其中任意一个依赖设置为属性依赖(属性依赖的处理,在bean实例建立完成且暴露earlySingleton以后)
@Component public class BeanA { @Autowired private BeanB beanB; } @Component public class BeanB { public BeanB(BeanC beanC) { } } @Bean public BeanC beanC(BeanA beanA) { return new BeanC(); }
或
@DependsOn("beanB") @Component public class BeanA { } @Component public class BeanB { private BeanC beanC; @Resource public void setBeanC(BeanC beanC) { this.beanC = beanC; } } @Bean public BeanC beanC(BeanA beanA) { return new BeanC(); }
等等
为了不无解的循环依赖,在构成循环依赖的一个环中,只须要保证其中至少一个bean的依赖在该bean建立且暴露earlySingleton以后处理便可
咱们以“bean建立且暴露earlySingleton”为节点,在此以前处理依赖的有instance supplier parameter
、factory method parameter
、constructor parameter
、等,在此以后处理的依赖有 class property
、setter parameter
、等
本文介绍了Spring体系内bean的建立及销毁过程,在通过万次的commit后,也造就了Spring必定程度上的复杂度
本文并未全方位的诠释bean的建立过程,文中遗留了不少疑问点,同时也能发现Spring提供了众多的扩展点来加强Ioc的能力,让开发者可以更好的使用/驾驭
下一篇文章,将着重介绍Spring本文中遗留的疑问点及Spring所提供的各类扩展能力
所在类 | 属性 | 类型 | 描述 |
---|---|---|---|
SimpleAliasRegistry | aliasMap | Map<String, String> | Map from alias to canonical name.<br/> 别名alias到原始bean-name的映射 |
DefaultSingletonBeanRegistry | earlySingletonObjects | Map<String, Object> | Cache of early singleton objects: bean name to bean instance<br/> 缓存提早曝光的singleton-bean-instance,主要用于解决循环依赖,存在于该处的实例还未执行属性依赖注入及其余后处理逻辑 |
singletonFactories | Map<String, ObjectFactory> | Cache of singleton factories: bean name to ObjectFactory.<br/> 缓存用于生成、获取earlySingletonObject的工厂方法 | |
singletonObjects | Map<String, Object> | Cache of singleton objects: bean name to bean instance.<br/> 缓存已经实例化的singleton-bean-instance | |
dependentBeanMap | Map<String, Set<String>> | Map between dependent bean names: bean name to Set of dependent bean names.<br/> 若是 beanA -> beanB, beanA -> beanC,key为beanA,value为[beanB, beanC] | |
dependenciesForBeanMap | Map<String, Set<String>> | Map between depending bean names: bean name to Set of bean names for the bean's dependencies.<br/> 若是 beanB -> beanA, beanC -> beanA,key为beanA,value为[beanB, beanC] | |
singletonsCurrentlyInCreation | Set<String> | Names of beans that are currently in creation.<br/> 缓存正在建立中的singleton-bean-name | |
registeredSingletons | Set<String> | Set of registered singletons, containing the bean names in registration order.<br/> 缓存已经建立的singleton-bean-name | |
disposableBeans | Map<String, Object> | Disposable bean instances: bean name to disposable instance.<br/> 缓存注册的可销毁bean(bean的销毁逻辑) | |
FactoryBeanRegistrySupport | factoryBeanObjectCache | Map<String, Object> | Cache of singleton objects created by FactoryBeans: FactoryBean name to object.<br/> 针对singleton,缓存FactoryBean获得的真正的singleton-bean-instance |