SpringBoot源码解读与原理分析(二十四)IOC容器的刷新(五)
文章目录
- 7.11 初始化所有剩下的单实例bean对象
- 7.11.1 beanFactory.preInstantiateSingletons
- 7.11.2 getBean
- 7.11.2.1 别名的解析处理
- 7.11.2.2 判断是否已注册过
- 7.11.2.3 创建前的检查
- 7.11.2.4 标记准备创建的bean对象
- 7.11.2.5 合并BeanDefinition
- 7.11.2.6 bean对象的创建
- 7.11.2.7 getSingleton控制单实例对象
- 7.11.3 createBean
- 7.11.3.1 resolveBeforeInstantiation
- 7.11.3.2 doCreateBean
- 1.实例化bean对象
- (1)解析bean对象的类型
- (2)处理Supplier创建和工厂方法创建
- (3)原型Bean的创建优化
- (4)实例化bean对象的真实动作
- 2.属性赋值前的注解信息收集
- (1)InitDestroyAnnotationBeanPostProcessor
- (2)CommonAnnotationBeanPostProcessor
- (3)AutowiredAnnotationBeanPostProcessor
- 3.早期bean对象引用的获取与缓存
- 4.属性赋值和依赖注入
- (1)回调InstantiationAwareBeanPostProcessor
- (2)再次回调InstantiationAwareBeanPostProcessor
- (3)属性赋值
- 5.bean对象的初始化
- (1)invokeAwareMethods——执行Aware类型接口的回调
- (2)applyBeanPostProcessorsBeforeInitialization——执行BeanPostProcessor的前置回调
- (3)invokeInitMethods——执行初始化生命周期回调
- (4)applyBeanPostProcessorsAfterInitialization——执行BeanPostProcessor的后置回调
- 6.注册销毁时的回调
- 7.11.4 SmartInitializingSingleton
前面四节,详细梳理了IOC容器刷新的前面十步(7.1-7.10)以及一个重要的后置处理器ConfigurationClassPostProcessor,详见:
SpringBoot源码解读与原理分析(二十)IOC容器的刷新(一)
SpringBoot源码解读与原理分析(二十一)IOC容器的刷新(二)
SpringBoot源码解读与原理分析(二十二)IOC容器的刷新(三)ConfigurationClassPostProcessor
SpringBoot源码解读与原理分析(二十三)IOC容器的刷新(四)
这一节继续梳理第十一步(7.11)。
本文超长预警,有1400+行。
代码清单1:AbstractApplicationContext.javapublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.// 7.1 初始化前的预处理prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 7.2 获取BeanFactory,加载所有bean的定义信息(未实例化)ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 7.3 BeanFactory的预处理配置prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 7.4 BeanFactory准备工作完成后的后置处理postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 7.5 BeanFactory创建后的后置处理器的执行invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 7.6 初始化Bean的后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 7.7 初始化MessageSourceinitMessageSource();// Initialize event multicaster for this context.// 7.8 初始化事件广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 7.9 子类扩展的刷新动作onRefresh();// Check for listener beans and register them.// 7.10 注册监听器registerListeners();// 至此,BeanFactory创建完成// Instantiate all remaining (non-lazy-init) singletons.// 7.11 初始化所有剩下的单实例bean对象finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 7.12 完成容器的创建工作finishRefresh();} catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;} finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...// 7.13 清理缓存resetCommonCaches();}}
}
7.11 初始化所有剩下的单实例bean对象
// 7.11 初始化所有剩下的单实例bean对象
finishBeanFactoryInitialization(beanFactory);
代码清单2:AbstractApplicationContext.javaprotected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 初始化类型转换器ConversionServiceif (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// 注册嵌入式值解析器EmbeddedValueResolverif (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}// 初始化LoadTimeWeaverAwareString[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}beanFactory.setTempClassLoader(null);// 冻结配置beanFactory.freezeConfiguration();// 实例化所有非延迟加载的单实例BeanbeanFactory.preInstantiateSingletons();
}
由 代码清单2 可知,finishBeanFactoryInitialization
方法前面的逻辑都是预备性的,其逻辑重点在最后一行beanFactory.preInstantiateSingletons
:实例化所有非延迟加载的单实例Bean。
7.11.1 beanFactory.preInstantiateSingletons
借助IDEA得知,preInstantiateSingletons
方法在ConfigurableListableBeanFactory中定义,最终实现在DefaultListableBeanFactory中。
代码清单3:DefaultListableBeanFactory.java@Override
public void preInstantiateSingletons() throws BeansException {// logger...List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);for (String beanName : beanNames) {// 先合并BeanDefinitionRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 不是抽象的、不是延迟加载的单实例Bean需要初始化if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);// 如果是FactoryBean默认不立即初始化if (bean instanceof FactoryBean) {// FactoryBean的处理逻辑}} else {// 普通的Bean的初始化getBean(beanName);}}}// ...
}
由 代码清单3 可知,在初始化所有非延迟加载的单实例bean对象时,会根据bean对象的类型分别处理。如果bean对象的类型是FactoryBean,会有单独的处理逻辑;而初始化普通bean对象时,使用的是getBean
方法。
7.11.2 getBean
代码清单4:AbstractBeanFactory.java@Override
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}
由 代码清单4 可知,getBean
方法会转调doGetBean
方法。doGetBean
方法的逻辑复杂,下面拆解来看。
7.11.2.1 别名的解析处理
代码清单5:AbstractBeanFactory.javaprotected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// 别名的解析处理String beanName = transformedBeanName(name);// ···
}protected String transformedBeanName(String name) {return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}public String canonicalName(String name) {String canonicalName = name;// Handle aliasing...String resolvedName;do {// 从别名集合中提取真实的名称resolvedName = this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}}while (resolvedName != null);return canonicalName;
}
在使用@Bean注解标注在方法上注册bean对象时,可以通过设置其name或value属性为bean对象指定名称。而name或value属性可以传入一个数组,意味着一个bean对象可以有多个名称,默认情况下传入的第一个属性值是bean对象的名称,其余的都是别名。
代码清单5 的逻辑就是处理这些别名:如果参数name是一个别名,则通过transformedBeanName
方法转换为真正的名称。
7.11.2.2 判断是否已注册过
代码清单6:AbstractBeanFactory.javaprotected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// ···// 先尝试从已经实例化好的Bean中找有没有当前Bean// 如果能找到,说明Bean已经被实例化了,直接返回Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {// logger ......bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);} else// ···
}protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {// ...// 如果不是FactoryBean,直接返回if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}// ...// 如果是FactoryBean,则调用getObject方法获取对象object = getObjectFromFactoryBean(factory, beanName, !synthetic);return object;
}
}
由 代码清单6 可知,第二步是尝试获取IOC容器中是否已创建并缓存当前正在获取的单实例bean对象,如果成功获取到,说明Bean已经被实例化了,直接返回。getObjectForBeanInstance
方法对返回的结果进行分类处理,如果获取到的bean对象是一个FactoryBean,则进行一些额外处理,并通过调用getObject
方法获取对象;如果是普通的bean对象,则直接返回。
7.11.2.3 创建前的检查
如果 代码清单6 中没有获取到bean对象,说明当前处理的Bean还未创建,即if逻辑判断为false,则进入else结构部分,开始创建该bean对象。
代码清单7:AbstractBeanFactory.javaprotected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// ···else {// 如果当前创建的bean对象是一个原型Bean并且正在创建,抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}BeanFactory parentBeanFactory = getParentBeanFactory();// 如果当前BeanFactory没有当前bean对象的BeanDefinition// 则通过父级BeanFactory返回if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);} else if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);} else if (requiredType != null) {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);} else {return (T) parentBeanFactory.getBean(nameToLookup);}}}// ···
}
由 代码清单7 可知,创建bean对象之前会进行校验,判断当前要创建的bean对象是否是一个原型Bean并且已经在创建了,如果是,说明当前原型Bean在一次获取中将产生两个对象,这种现象不合理,所以会抛出异常。
第二项校验是判断当前BeanFactory是否包含当前bean对象的BeanDefinition,如果没有,则通过父级BeanFactory的doGetBean
方法或getBean
方法返回(BeanFactory的层次性的体现)。
7.11.2.4 标记准备创建的bean对象
代码清单8:AbstractBeanFactory.javaprotected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// ···else {// ...if (!typeCheckOnly) {markBeanAsCreated(beanName);}// ...}// ···
}protected void markBeanAsCreated(String beanName) {if (!this.alreadyCreated.contains(beanName)) {synchronized (this.mergedBeanDefinitions) {if (!this.alreadyCreated.contains(beanName)) {clearMergedBeanDefinition(beanName);this.alreadyCreated.add(beanName);}}}
}
由 代码清单8 可知,在确认Bean确需创建之后,会对其名称进行标记。markBeanAsCreated
方法会将当前正在处理的bean对象的名称放入alreadyCreated集合中,代表该bean对象已被创建。
7.11.2.5 合并BeanDefinition
代码清单9:AbstractBeanFactory.javaprotected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// ···else {// ...try {// 合并BeanDefinitionRootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// 处理当前bean对象的依赖(@DependsOn注解)String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {// 注册并初始化依赖的bean对象registerDependentBean(dep, beanName);try {getBean(dep);} // catch ...}}}// ...} // catch...}// ···
}
由 代码清单9 可知,合并BeanDefinition的getMergedLocalBeanDefinition
方法可以得到当前正在创建的bean对象需要依赖哪些bean对象,也就是在当前创建的bean对象中显式标注了@DependsOn注解的属性。
由于标注了@DependsOn注解的属性代表强制依赖,IOC容器会优先处理这些被强制依赖的bean对象并将其初始化,而初始化的方式依然是getBean
方法。
7.11.2.6 bean对象的创建
代码清单10:AbstractBeanFactory.javaprotected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// ···else {// ...try {// ...// 单实例singleton作用域if (mbd.isSingleton()) {// 每次调用createBean返回的都是同一个实例sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);} // catch...});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);} // 原型prototype作用域else if (mbd.isPrototype()) {// 每次调用createBean都会创建一个新的实例Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);} finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);} // 其他作用域else {String scopeName = mbd.getScope();// ...try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);} finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);} // catch...}} // catch...}// ···
}
由 代码清单10 可知,经过多步的检查和前置处理之后,bean对象终于开始创建。IOC容器会根据当前正在创建的bean对象的作用域(单实例singleton作用域、原型prototype作用域或其他)决定如何创建对象。
但不管是哪些作用域,底层都是调用createBean
方法创建对象。不同的是,对于单实例singleton作用域,每次调用createBean
方法返回的都是同一个实例;对于原型prototype作用域,每次调用createBean
方法都会创建一个新的实例。
IOC容器中控制单实例对象的方式是使用getSingleton
方法配合ObjectFactory实现的。
7.11.2.7 getSingleton控制单实例对象
代码清单11:DefaultSingletonBeanRegistry.javaprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {// 加锁后,从缓存集合中提取bean对象实例Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {// 如果缓存中没有,则创建对象if (this.singletonsCurrentlyInDestruction) {// throw ...}if (logger.isDebugEnabled()) {// logger ...}beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {// 调用getObject方法就是外层调用createBean方法singletonObject = singletonFactory.getObject();newSingleton = true;} // catch finally...// 新创建的单实例bean对象存入缓存中if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}
}
由 代码清单11 可知,控制单实例bean对象的方式借助一个名为singletonObjects的Map集合充当缓存区,在获取单实例bean对象时,会先从缓存区中尝试获取,如果没有获取到则会调用createBean
方法创建对象,并保存到singletonObjects缓存中。
简言之,单实例bean对象在第一次创建时会调用createBean
方法真正地创建对象,创建完毕会存入IOC容器底层的singletonObjects缓存区,后续再次获取时会直接从缓存区中取出bean对象并返回。
7.11.3 createBean
代码清单12:AbstractAutowireCapableBeanFactory.javaprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// logger ...}RootBeanDefinition mbdToUse = mbd;// 根据BeanDefinition获取当前正在创建的bean对象的类型Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// ...try {// 后置处理器BeanPostProcessors拦截创建bean对象Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}} // catch ...try {// 真正创建bean对象Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;} // catch ...
}
由 代码清单12 可知,实际创建bean对象有两个切入点:
- 通过
resolveBeforeInstantiation
方法创建bean对象:由方法名可以理解为“实例化之前的处理”,因此这只是创建bean对象之前的拦截。 - 通过
doCreateBean
方法实际创建bean对象。
7.11.3.1 resolveBeforeInstantiation
代码清单13:AbstractAutowireCapableBeanFactory.javaprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {// 执行所有InstantiationAwareBeanPostProcessorbean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {// 如果成功创建了bean对象,则执行所有的BeanPostProcessorsbean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;
}protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {// 循环找出所有的InstantiationAwareBeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// 调用其postProcessBeforeInstantiation方法实例化对象Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;
}@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 循环找出所有的BeanPostProcessorfor (BeanPostProcessor processor : getBeanPostProcessors()) {// 调用其postProcessAfterInitialization方法增强对象Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}
由 代码清单14 可知,拦截bean对象的创建行为有两步:先执行所有InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation
方法创建对象,如果成功创建bean对象,在执行所有BeanPostProcessors的postProcessAfterInitialization
方法增强对象。
以上两个后置处理器的底层逻辑基本一致,都是从IOC容器获取到所有注册的后置处理器,并逐一回调。
7.11.3.2 doCreateBean
如果resolveBeforeInstantiation
方法没有创建出bean对象,则需要执行doCreateBean
方法创建bean对象的实例。doCreateBean
方法的逻辑非常长,下面拆解来看。
1.实例化bean对象
代码清单14:AbstractAutowireCapableBeanFactory.javaprotected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// ...if (instanceWrapper == null) {// 创建bean对象实例instanceWrapper = createBeanInstance(beanName, mbd, args);}// 得到bean对象的引用Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// ...
}
由 代码清单14 可知,实例化bean对象是创建对象的第一步,即createBeanInstance
方法。
(1)解析bean对象的类型
代码清单15:AbstractAutowireCapableBeanFactory.javaprotected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 解析出bean对象的类型Class<?> beanClass = resolveBeanClass(mbd, beanName);// 如果bean对象无法被访问,则抛出异常if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());}// ...
}
由 代码清单15 可知,createBeanInstance
方法首先会检验当前要创建的bean对象所属类型是否可以被正常访问,如果不可以,则会抛出异常。
(2)处理Supplier创建和工厂方法创建
代码清单16:AbstractAutowireCapableBeanFactory.javaprotected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// ...//如果制定了实例Supplier,则通过Supplier实例化bean对象Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// 如果指定了工厂方法,则通过工厂方法实例化bean对象if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// ...
}/*** Obtain a bean instance from the given supplier.*/
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
由 代码清单16 可知,如果BeanDefinition中指定了实例Supplier,则通过Supplier实例化bean对象。obtainFromSupplier
方法的 javadoc 指出,这个方法可以从给定的Supplier中得到bean实例。
如果BeanDefinition中指定了工厂方法,则通过工厂方法实例化bean对象。
(3)原型Bean的创建优化
代码清单17:AbstractAutowireCapableBeanFactory.javaprotected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// ...boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {// 直接从BeanDefinition中取出构造方法以实例化对象return autowireConstructor(beanName, mbd, null, null);}else {// 通过构造方法实例化对象return instantiateBean(beanName, mbd);}}// ...
}
由 代码清单17 可知,这一段代码是针对原型Bean而言的,在第一次原型bean对象创建完成后,将创建过程中引用的构造方法缓存到BeanDefinition中,以备后续创建时可以直接取出。
(4)实例化bean对象的真实动作
代码清单18:AbstractAutowireCapableBeanFactory.javaprotected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// ...// 回调SmartInstantiationAwareBeanPostProcessor寻找构造方法Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 条件1:通过SmartInstantiationAwareBeanPostProcessor找到了构造方法// 条件2:配置自动注入方式为AUTOWIRE_CONSTRUCTOR// 条件3:使用XML配置文件的方式定义Bean时指定了constructor-arg标签// 条件4:调用getBean方法获取bean对象时传入了args参数if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {// 使用显式构造方法实例化bean对象return autowireConstructor(beanName, mbd, ctors, args);}// 如果BeanDefinition中指定了首选构造函数,也使用显式构造方法实例化bean对象ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// 使用无参数构造方法实例化bean对象return instantiateBean(beanName, mbd);
}
由 代码清单18 可知,当触发一些条件时,IOC容器会选择使用显式构造方法实例化bean对象。
- 条件1:通过SmartInstantiationAwareBeanPostProcessor找到了构造方法;
- 条件2:配置自动注入方式为AUTOWIRE_CONSTRUCTOR;
- 条件3:使用XML配置文件的方式定义Bean时指定了constructor-arg标签;
- 条件4:调用getBean方法获取bean对象时传入了args参数;
- 条件5:BeanDefinition中指定了首选构造函数。
如果以上条件都不满足,则会使用默认的无参构造方法创建对象。
代码清单19:AbstractAutowireCapableBeanFactory.javaprotected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {try {Object beanInstance;// 借助InstantiationStrategy实例化对象if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),getAccessControlContext());} else {beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);}BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;} // catch ...
}@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// ...return BeanUtils.instantiateClass(constructorToUse);
}
由 代码清单19 可知,instantiateBean
的重点在于获取InstantiationStrategy,使用BeanUtils.instantiateClass
方法反射实例化bean对象。
经过createBeanInstance
方法后,即可得到一个对象内部没有任何额外注入的bean对象,bean对象的实例化完毕。
2.属性赋值前的注解信息收集
回到doCreateBean
方法,实例化bean对象之后,进入属性赋值前的注解信息收集。
代码清单20:AbstractAutowireCapableBeanFactory.javaprotected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// ...synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);} // catch ...mbd.postProcessed = true;}}// ...
}protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof MergedBeanDefinitionPostProcessor) {MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);}}
}
由 代码清单20 可知,核心方法applyMergedBeanDefinitionPostProcessors
会回调所有的MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition
方法。借助IDEA可知,有几个重要的后置处理器实现了该方法。
(1)InitDestroyAnnotationBeanPostProcessor
代码清单21:InitDestroyAnnotationBeanPostProcessor.java@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {LifecycleMetadata metadata = findLifecycleMetadata(beanType);metadata.checkConfigMembers(beanDefinition);
}private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {// ...return buildLifecycleMetadata(clazz);
}private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {// ...List<LifecycleElement> initMethods = new ArrayList<>();List<LifecycleElement> destroyMethods = new ArrayList<>();Class<?> targetClass = clazz;do {final List<LifecycleElement> currInitMethods = new ArrayList<>();final List<LifecycleElement> currDestroyMethods = new ArrayList<>();// 反射所有的public方法ReflectionUtils.doWithLocalMethods(targetClass, method -> {// 寻找所有被@PostConstruct注解标注的方法if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {LifecycleElement element = new LifecycleElement(method);currInitMethods.add(element);// logger ...}// 寻找所有被@PostDestroy注解标注的方法if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {currDestroyMethods.add(new LifecycleElement(method));// logger ...}});initMethods.addAll(0, currInitMethods);destroyMethods.addAll(currDestroyMethods);// 依次向上寻找父类targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);// return ...
}
由 代码清单21 可知,postProcessMergedBeanDefinition
方法会扫描和收集当前正在创建的bean对象中标注了@PostConstruct注解和@PostDestroy注解的方法。源码中的initAnnotationType对应@PostConstruct注解,destroyAnnotationType对应@PostDestroy注解。
(2)CommonAnnotationBeanPostProcessor
代码清单22:CommonAnnotationBeanPostProcessor.java@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {// 调用父类InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);
}private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {// ...metadata = buildResourceMetadata(clazz);// ...
}private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {// ...do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();ReflectionUtils.doWithLocalFields(targetClass, field -> {// @WebServiceRefif (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {if (Modifier.isStatic(field.getModifiers())) {throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");}currElements.add(new WebServiceRefElement(field, field, null));} // @EJBelse if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {if (Modifier.isStatic(field.getModifiers())) {throw new IllegalStateException("@EJB annotation is not supported on static fields");}currElements.add(new EjbRefElement(field, field, null));} // @Resourceelse if (field.isAnnotationPresent(Resource.class)) {if (Modifier.isStatic(field.getModifiers())) {throw new IllegalStateException("@Resource annotation is not supported on static fields");}if (!this.ignoredResourceTypes.contains(field.getType().getName())) {currElements.add(new ResourceElement(field, field, null));}}});// ...elements.addAll(0, currElements);// 依次向上寻找父类targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);
}
由 代码清单22 可知,CommonAnnotationBeanPostProcessor的父类是InitDestroyAnnotationBeanPostProcessor,所以它也具备收集@PostConstruct注解和@PostDestroy注解的能力,同时还具备收集JSR-250规范中的注解(如@WebServiceRef、@EJB、 @Resource)的能力。
(3)AutowiredAnnotationBeanPostProcessor
代码清单23:AutowiredAnnotationBeanPostProcessor.javapublic AutowiredAnnotationBeanPostProcessor() {this.autowiredAnnotationTypes.add(Autowired.class);this.autowiredAnnotationTypes.add(Value.class);try {this.autowiredAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");} // catch ...
}@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);
}
由 代码清单24 可知,AutowiredAnnotationBeanPostProcessor具备的能力是收集@Autowired、@Value、@Inject注解,收集原理和前面两者后置处理器的原理一致。
3.早期bean对象引用的获取与缓存
回到doCreateBean
方法,收集完属性赋值前的注解信息之后,开始收集早期bean对象引用。
代码清单25:AbstractAutowireCapableBeanFactory.javaprotected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// ...boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// 处理循环依赖的问题addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// ...
}
由 代码清单25 可知,bean对象实例化之后,虽然没有进行属性赋值和依赖注入,但也已经是一个实实在在的对象。如果在此期间有另外的bean对象需要依赖它,就不应该再创建一个新的bean对象,而是直接获取当前bean对象的引用即可。
这个设计就是为了解决bean对象之间的循环依赖。
4.属性赋值和依赖注入
回到doCreateBean
方法,处理早期bean对象引用之后,开始进行属性赋值和依赖注入。
代码清单26:AbstractAutowireCapableBeanFactory.javaprotected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// ...// Initialize the bean instance.Object exposedObject = bean;try {// 属性赋值和依赖注入populateBean(beanName, mbd, instanceWrapper);// bean对象的初始化exposedObject = initializeBean(beanName, exposedObject, mbd);} // catch ...// ...
}
(1)回调InstantiationAwareBeanPostProcessor
代码清单27:AbstractAutowireCapableBeanFactory.javaprotected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 前置检查 ...// 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.// 在设置属性之前,让任何InstantiationAwareBeanPostProcessors都有机会修改// Bean的状态,例如支持属性字段的注入。if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}}// ...
由 代码清单27 可知,InstantiationAwareBeanPostProcessors是一个可以干预Bean的属性、状态等信息的后置处理器。其postProcessAfterInstantiation
方法的返回值是boolean类型,当返回false时直接结束populateBean
方法,不再执行真正的属性赋值+组件依赖注入的逻辑。
这样设计的目的在于,允许开发者在bean对象已经实例化完毕但还没有开始属性赋值和依赖注入时切入自定义逻辑。
(2)再次回调InstantiationAwareBeanPostProcessor
代码清单28:AbstractAutowireCapableBeanFactory.javaprotected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// ...for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);// ...}}// ...
由 代码清单28 可知,populateBean
方法会再一次回调InstantiationAwareBeanPostProcessor,但这次调用的是其postProcessProperties
方法,作用是执行组件的依赖注入。
负责依赖注入的后置处理器是前面提到的AutowiredAnnotationBeanPostProcessor。
代码清单29:AutowiredAnnotationBeanPostProcessor.java@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs);} // catch ...
}public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;// 取出在前面收集的@Autowired、@Value、@Inject注解Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {// 逐个注入for (InjectedElement element : elementsToIterate) {element.inject(target, beanName, pvs);}}
}
由 代码清单29 可知,在进行依赖注入时,首先会取出前面步骤收集的所有标注了@Autowired、@Value、@Inject注解的方法,封装为InjectionMetadata,并调用其inject
方法进行依赖注入。
(3)属性赋值
代码清单30:AbstractAutowireCapableBeanFactory.javaprotected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// ...PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);// ...if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs != null) {// 应用PropertyValues对象到当前正在创建的bean对象applyPropertyValues(beanName, mbd, bw, pvs);}
由 代码清单30 可知,经过前面几个步骤之后,生成了一个PropertyValues对象,该对象封装了当前正在创建的bean对象中需要依赖的所有属性赋值类元素,最后执行的applyPropertyValues
方法就是把前面准备好的PropertyValues对象封装的内容应用到当前正在创建的bean对象实例中。
在applyPropertyValues
方法内部,会将属性值反射注入bean对象的成员属性中。
经过该阶段,bean对象的属性赋值和依赖注入工作完成。
5.bean对象的初始化
由 代码清单26 可知,属性赋值和依赖注入完成后,立刻开始初始化bean对象,即initializeBean
方法。
代码清单31:AbstractAutowireCapableBeanFactory.javaprotected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {// 执行Aware类型接口的回调invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());} else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 执行BeanPostProcessor的前置回调wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 执行生命周期回调invokeInitMethods(beanName, wrappedBean, mbd);} // catch ...if (mbd == null || !mbd.isSynthetic()) {// 执行BeanPostProcessor的后置回调wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}
由 代码清单31 可知,initializeBean
方法包含4个回调逻辑。
(1)invokeAwareMethods——执行Aware类型接口的回调
代码清单32:AbstractAutowireCapableBeanFactory.javaprivate void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}
由 代码清单32 可知,invokeAwareMethods
方法会判断当前bean对象是否实现了特定的Aware接口,如果实现了就强转后掉哟个对应的setter方法。
(2)applyBeanPostProcessorsBeforeInitialization——执行BeanPostProcessor的前置回调
代码清单33:AbstractAutowireCapableBeanFactory.javapublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName);// 如果一个BeanPostProcessor处理bean对象后返回的结果为null// 则不再执行剩余的BeanPostProcessor// 而直接返回上一个BeanPostProcessor处理之后的bean对象if (current == null) {return result;}result = current;}return result;
}
由 代码清单33 可知,该回调逻辑是执行BeanPostProcessor的postProcessBeforeInitialization
方法。
在这中间有一个特殊的设计:如果一个BeanPostProcessor处理bean对象后返回的结果为null,则不再执行剩余的BeanPostProcessor,而直接返回上一个BeanPostProcessor处理之后的bean对象。这样设计的目的,是方便开发者在设计postProcessBeforeInitialization
方法时,可以通过控制其返回值以进行特殊处理。
下面介绍两个后置处理器实现类。
- InitDestroyAnnotationBeanPostProcessor
代码清单34:InitDestroyAnnotationBeanPostProcessor.java@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 收集标注了@PostConstruct和@PreDestroy的方法InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {// 执行初始化方法metadata.invokeInitMethods(bean, beanName);} // catch ...return bean;
}public void invokeInitMethods(Object target, String beanName) throws Throwable {Collection<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> checkedInitMethods = this.checkedInitMethods;Collection<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethodsToIterate =(checkedInitMethods != null ? checkedInitMethods : this.initMethods);if (!initMethodsToIterate.isEmpty()) {for (InitDestroyAnnotationBeanPostProcessor.LifecycleElement element : initMethodsToIterate) {// logger ...element.invoke(target);}}
}public void invoke(Object target) throws Throwable {ReflectionUtils.makeAccessible(this.method);this.method.invoke(target, (Object[]) null);
}
由 代码清单34 可知,postProcessBeforeInitialization
方法首先会收集标注了@PostConstruct和@PreDestroy的方法(收集方法详见【7.11.3.2 2.属性赋值前的注解信息收集 (1)InitDestroyAnnotationBeanPostProcessor】),然后回调bean对象中所有标注了@PostConstruct注解的方法。
由ReflectionUtils.makeAccessible(this.method);
可知,反射执行目标方法时会先借助ReflectionUtils获取其访问权,这意味着对于使用@PostConstruct注解标注的方法的访问修饰符没有强限制。
由this.method.invoke(target, (Object[]) null);
可知,最终回调方法时传入的参数时空对象,这也解释了为什么在使用@PostConstruct注解标注方法时一定要设置为空参数方法。
- ApplicationContextAwareProcessor
代码清单35:ApplicationContextAwareProcessor.java@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 不是这6个Aware子接口的,不予处理if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){return bean;}// ...else {invokeAwareInterfaces(bean);}return bean;
}private void invokeAwareInterfaces(Object bean) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}
}
由 代码清单35 可知,ApplicationContextAwareProcessor支持6个Aware子接口的回调注入,否则不予处理。执行Aware子接口时根据不同类型执行setter方法。
(3)invokeInitMethods——执行初始化生命周期回调
代码清单36:AbstractAutowireCapableBeanFactory.javaprotected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {// ...} else {// 回调InitializingBean的afterPropertiesSet方法((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// 反射回调init-method方法invokeCustomInitMethod(beanName, bean, mbd);}}
}
由 代码清单36 可知,初始化生命周期回调包括init-method方法和InitializingBean接口的初始化逻辑回调。
(4)applyBeanPostProcessorsAfterInitialization——执行BeanPostProcessor的后置回调
代码清单37:AbstractAutowireCapableBeanFactory.java@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}
由 代码清单37 可知,回调BeanPostProcessor的后置拦截的逻辑和前置拦截几乎一致。重点关注两个后置处理器的实现。
- AbstractAutoProxyCreator
所有以AutoProxyCreator结尾的类都与AOP相关,且都是具备代理对象创建能力的后置处理器,可以在bean对象本身的初始化逻辑完成后根据需要创建代理对象。
- ApplicationListenerDetector
ApplicationListenerDetector的作用是关联事件广播器和监听器的引用,因此在创建ApplicationListener类型的bean对象时,ApplicationListenerDetector会检测并将其添加到ApplicationContext中,关联ApplicationEventMulticaster事件广播器。
6.注册销毁时的回调
回到doCreateBean
方法,bean对象初始化之后,最后一步是注册销毁时的回调。
代码清单38:AbstractAutowireCapableBeanFactory.javaprotected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// ...try {// 注册销毁时的回调registerDisposableBeanIfNecessary(beanName, bean, mbd);} // catch ...// ...
}protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);// 不是原型Bean,且定义了销毁类型的方法if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {if (mbd.isSingleton()) {// 注册一个执行给定bean对象的所有销毁工作的DisposableBean实现:Destruction// 通过实现DisposableBean接口,或自定义销毁方法。registerDisposableBean(beanName,new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));} // else...}
}
由 代码清单38 可知,如果一个bean对象的所属类型实现了DisposableBean接口,或者内部方法中标注了@PreDestory注解,或者声明了destory-method方法,则会在doCreateBean
方法的最后阶段注册一个销毁bean对象的回调钩子,在IOC容器关闭时,这部分bean对象会回调其自定义的自毁逻辑。
至此,doCreateBean
方法执行完毕,一个bean对象被创建完成并返回。
7.11.4 SmartInitializingSingleton
回到preInstantiateSingletons
方法,在bean对象创建完成后,还有一段额外的逻辑。
代码清单39:DefaultListableBeanFactory.java@Override
public void preInstantiateSingletons() throws BeansException {// ...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}
}
由 代码清单39 可知,如果bean对象实现了SmartInitializingSingleton接口,则遍历回调其afterSingletonsInstantiated
方法。这实际上是在非延迟加载的单实例bean对象全部创建完成后提供一个统一的扩展回调时机,以便在ApplicationContext初始化完成之前处理一些特殊的逻辑。
经过上述一系列复杂逻辑后,finishBeanFactoryInitialization
方法执行完毕,所有非延迟加载的单实例bean对象全部完成创建并初始化。
······
至此,IOC容器的刷新完成了前面十一步,分别是:
7.1 初始化前的预处理
7.2 初始化BeanFactory
7.3 BeanFactory的预处理配置
7.4 BeanFactory准备工作完成后的后置处理
7.5 BeanFactory创建后的后置处理器的执行
7.6 初始化Bean的后置处理器
7.7 初始化国际化组件
7.8 初始化事件广播器
7.9 子类扩展的刷新动作
7.10 注册监听器
7.11 初始化所有剩下的单实例bean对象
本节完,更多内容请查阅分类专栏:SpringBoot源码解读与原理分析
相关文章:

SpringBoot源码解读与原理分析(二十四)IOC容器的刷新(五)
文章目录 7.11 初始化所有剩下的单实例bean对象7.11.1 beanFactory.preInstantiateSingletons7.11.2 getBean7.11.2.1 别名的解析处理7.11.2.2 判断是否已注册过7.11.2.3 创建前的检查7.11.2.4 标记准备创建的bean对象7.11.2.5 合并BeanDefinition7.11.2.6 bean对象的创建7.11.…...

最大子数组和
一、题目 给你一个整数数组nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#…...

Node.js版本管理工具之_Volta
Node.js包管理工具之_Volta 文章目录 Node.js包管理工具之_Volta1. 官网1. 官网介绍2. 特点1. 快( Fast)2. 可靠(Reliable)3. 普遍( Universal) 2. 下载与安装1. 下载2. 安装3. 查看 3. 使用1. 查看已安装的工具包2. 安装指定的node版本3.切换项目中使用的版本 1. 官网 1. 官网…...

Redis 命令大全
文章目录 启动与连接Key(键)相关命令String(字符串)Hash(哈希)List(列表)Set(集合)Sorted Set(有序集合)其他常见命令HyperLogLog&…...

再这么烂下去,离糊就不远了。别让才华被埋没。
♥ 为方便您进行讨论和分享,同时也为能带给您不一样的参与感。请您在阅读本文之前,点击一下“关注”,非常感谢您的支持! 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 近日,胡歌凭借电视剧《繁花》荣登《环球银幕》二月…...

Unity BuffSystem buff系统
Unity BuffSystem buff系统 一、介绍二、buff系统架构三、架构讲解四、框架使用buff数据Json数据以及工具ShowTypeBuffTypeMountTypeBuffOverlapBuffShutDownTypeBuffCalculateType时间和层数这里也不过多说明了如何给生物添加buff 五、总结 一、介绍 现在基本做游戏都会需要些…...

Android rom定制 修改system分区的容量大小
1、写在前面 系统ROM定制化,预置app太多,会导致系统rom很大,原生系统system分区已经不够用了,要加大系统systemui分区 2.修改system分区的容量大小的核心类 device/mediatekprojects/$project/BoardConfig.mk build/make/core/Makefile3、修改system 分区的容量大小的核…...

速盾:服务器接入免备案CDN节点的好处有哪些
本文将探讨服务器接入免备案CDN节点的好处,包括提高网站的访问速度、增加网站的稳定性和可靠性、降低带宽成本等方面的优势。同时,还将提供一些相关问题的解答,帮助读者更好地了解这一技术。 随着互联网的迅猛发展,网站的访问速度…...

Redisson看门狗机制
一、背景 网上redis分布式锁的工具方法,大都满足互斥、防止死锁的特性,有些工具方法会满足可重入特性。如果只满足上述3种特性会有哪些隐患呢?redis分布式锁无法自动续期,比如,一个锁设置了1分钟超时释放,…...

【Java数据结构】双向 不带头 非循环 链表实现(模拟实现LinkedList类)
LinkedList底层实际上是双向、不带头结点、非循环的链表 链表的分类有八种,常用的有两种:一是单向、不带头结点、非循环的(基本上网上的题型都是这种);二是双向、不带头结点、非循环(LinkedList的底层实现…...

深度学习系列55:深度学习加速技术概述
总体有两个方向:模型优化 / 框架优化 1. 模型优化 1.1 量化 最常见的量化方法为线性量化,权重从float32量化为int8,将输入数据映射在[-128,127]的范围内。在 nvdia gpu,x86、arm 和 部分 AI 芯片平台上,均支持 8bit…...

使用python启动一个roslaunch文件
roslaunch 的实现源码主要位于 ROS 的 ros_comm 仓库中的 tools/roslaunch 目录下。源码主要由 Python 脚本和少量的 C 代码组成。 在Python程序中导入roslaunch包并启动一个ROS launch文件,你需要确保ROS环境已经设置好,并且相关的roslaunch包已经安装…...

JavaEE企业级应用软件开发—Spring框架入门学习笔记(一)
一、认识框架 实际开发中,随着业务的发展,软件系统变得越来越复杂,如果所有的软件都从底层功能开始开发,那将是一个漫长而繁琐的过程。此外,团队协作开发时,由于没有统一的调用规范,系统会出现大…...

ElasticSearch-SpringBoot整合ElasticSearch
六、SpringBoot整合ElasticSearch 1、浏览官方文档 1、查找跟ES客户端相关的文档 使用Java REST Client 选择Java Hight Level REST Client 2、创建项目的准备 1.找到原生的依赖 2.找到对象 3.分析这个类里面的方法 3、正式创建项目 1.创建工程 2.导入依赖 注意依赖版本…...

用云手机打造tiktok账号需要注意些什么?
随着tiktok平台的火热,越来越多的商家开始尝试更高效的tiktok运营方法。其中,tiktok云手机作为一种新科技引起了很多人的注意,那么用云手机运营tiktok需要注意些什么?下文将对此进行详细解析。 1. 不是所有的云手机都适合做tiktok…...

MySQL基础查询篇(9)-数学函数在查询中的应用
在MySQL数据库中,数学函数在查询中扮演了非常重要的角色。这些函数可以帮助我们进行各种数学计算和处理,使得我们能够更有效地处理和分析数据。本文将介绍一些常用的MySQL数学函数及其在查询中的应用。 1. ABS函数 ABS函数用于返回一个数值的绝对值。在…...

c#内置委托
C#语言中有许多内置的委托,其中一些是常用的,包括: Action:表示不带返回值的方法的委托。它可以接受多个参数,但不返回任何值。 Action<int, string> actionDelegate (x, y) > Console.WriteLine("Ac…...

【自动化测试】---Selenium+Java
1.自动化测试分类 接口自动化测试UI自动化测试(移动端自动化测试、Web端自动化测试) 2.选择Selenium作为web自动化工具原因(面试题) 开源免费支持多个浏览器支持多个系统支持多语言Selenium包提供很多供测试使用的API 3.自动化是什…...

uniapp新增一条数据增加一个折叠栏
//折叠栏 <uni-collapse classcollapse refcollapse><uni-collapse-item v-for"(item, index) in dataForm.beefCattleNums" :key"index" :title"item.fatCalfNum" classcollapse-item title-bordershow :borderfalse clicktoggleItem(…...

【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
Netty强大特性之Native transports技术原理分析 背景介绍JNI概念介绍不同平台的JNI实现 使用Native transports库Maven的分类器(Classifier)使用Linux native transport使用MacOS/BSD native transport库构建native transport库Linux版本要求MacOS/BSD版…...

1-1 动手学深度学习v2-线性回归-笔记
简化核心模型 假设1: 影响房价的关键因素是卧室个数,卫生间个数和居住面积,记为 x 1 x_{1} x1, x 2 x_{2} x2, x 3 x_{3} x3假设2: 成交价是关键因素的加权和 y w 1 x 1 w 2 x 2 w 3 x 3 b yw_{1}x_{1}w_{2}x_{2}w_{3…...

算法每日一题: 使用循环数组所有元素相等的最少秒数 | 哈希
大家好,我是星恒,今天给大家带来的是一道需要感觉规律的题目,只要读懂题目中的规律,就可以做出来了 这道题用到了哈希,还有一个关键点比较类似循环队列 题目:leetcode 2808 给你一个下标从 0 开始长度为 n…...

canvas实现涂鸦画板功能
查看专栏目录 canvas实例应用100专栏,提供canvas的基础知识,高级动画,相关应用扩展等信息。canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重…...

6-3、T型加减速单片机程序【51单片机+L298N步进电机系列教程】
↑↑↑点击上方【目录】,查看本系列全部文章 摘要:根据前两节内容,已完成所有计算工作,本节内容介绍具体单片机程序流程及代码 一、程序流程图 根据前两节文章内容可知,T型加减速的关键内容是运动类型的判断以及定时…...

Flutter组件 StatefulWidget、StatelessWidget 可继承写法
前言 学过Java的同学,应该都知道面向对象语言的三大特征,封装、继承、多态; Dart也是面向对象的语言,但是在Flutter中的很多组件都被下划线 _ 标记为私有,导致无法继承,本文将介绍一种非私有的创建组件写…...

skywalking链路追踪
skywalking 1.简介1.1 skywalking介绍1.2 链路追踪框架对比1.3 Skywalking架构 2 环境构建2.1 windows环境2.1.1 启动skywalking服务和UI界面2.1.2 在IDEA启动项目中使用Skywalking2.1.3 skywalking持久化 2.2 linux环境 1.简介 微服务架构已经是一个很通用的系统架构…...

如何在苹果Mac上进行分屏,多任务处理?
Apple 在 macOS Catalina 中引入了 Split View,让您可以同时查看两个应用程序。如果同时处理多个应用程序,但在它们之间切换时感到沮丧,小编教给大家在 Macbook Pro/Air 或 iMac 上使用分屏功能流畅地进行多任务处理。 注意:您可…...

【Java EE】----Spring框架创建和使用
1.Spring框架创建 创建一个maven项目 添加Spring框架支持 <dependencies> 上下文<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></depende…...

UE4 C++ 静态加载类和资源
静态加载类和资源:指在编译时加载,并且只能在构造函数中编写代码 .h //增加所需组件的头文件 #include "Components/SceneComponent.h" //场景组件 #include "Components/StaticMeshComponent.h" //静态网格体组件 #include &qu…...

洛谷C++简单题小练习day9—[AHOI2017]寻找探监点
day9--[AHOI2017]寻找探监点--2.7 习题概述 题目描述 一个nn 的网格图(标号由 1,1 开始)上有 m 个探测器,每个探测器有个探测半径 r ,问这 nn 个点中有多少个点能被探测到。 输入格式 第一行 3 个整数 n,m,r。 接下来 m 行&…...