欢迎大家来到IT世界,在知识的湖畔探索吧!
上一篇文章,因为要做一个分享所以简单的总结了一下 Spring IoC相关的知识点。今天这篇文章还是接着之前没写完的 IoC 的部分继续往下写。在上上篇文章 Spring 对象注入循环依赖框架是怎么帮我们做的? 分析了 IOC 总循环依赖的处理(掘金的图片显示不出来,这里是本人微信公众号里面的文章)。在Spring 注入对象处理过程中详细分析了对象的注入,其中涉及到一个非常重要的方法populateBean() 在该方法中完成了 Bean 依赖关系的处理。今天分析在对象之间的依赖关系处理完成之后,Spring是如何初始化 Bean 的。
Bean的初始化
Bean 的初始化方法入口如下:

欢迎大家来到IT世界,在知识的湖畔探索吧!
首先简单的总结一下这个方法的处理过程,分为如下几个步骤:
- Aware 系列接口的回调
- 执行 BeanPostProcessors 的 applyBeanPostProcessorsBeforeInitialization 方法
- 激活用户自定义的 init 方法
- 执行 BeanPostProcessors 的 applyBeanPostProcessorsAfterInitialization 方法
方法实现如下
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { / * 对特殊的bean处理:Aware,BeanClassLoaderAware,BeanFactoryAware */ invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { / 执行BeanPostProcessors的before 方法*/ wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { / * 激活用户自定义的 init 方法 */ invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { / 执行BeanPostProcessors的after 方法*/ wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } 复制代码
欢迎大家来到IT世界,在知识的湖畔探索吧!
1. Aware 系列接口的回调
在上述代码中,Aware 接口的回调是通过 invokeAwareMethods(beanName, bean); 来完成的。在这个方法中,对特殊的bean处理:Aware,BeanClassLoaderAware,BeanFactoryAware等。
欢迎大家来到IT世界,在知识的湖畔探索吧!private void invokeAwareMethods(final String beanName, final 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); } } } 复制代码
Aware 系列的接口
常用的Aware相关接口作用说明
名称作用ApplicationContextAware获取spring 上下文环境的对象BeanNameAware获取该bean在BeanFactory配置中的名字BeanFactoryAware创建它的BeanFactory实例
以 ApplicationContextAware 为例简单做一个使用说明,在 Spring 官网中主要介绍了这个类,官方文档还是要多看看的…测试代码如下:
启动类:
public class MyTestStart { public static void main(String[] args) { // Aware 使用测试 ApplicationContext ann = new AnnotationConfigApplicationContext(MyConfig.class); MyAwareTestService service = (MyAwareTestService) ann.getBean("myAwareTestService"); service.myTest(); service.myTest(); } } 复制代码
单例的Bean:
欢迎大家来到IT世界,在知识的湖畔探索吧!@Service("myAwareTestService") public class MyAwareTestService { @Autowired Test test; @Autowired TestAware1 testAware1; public void myTest(){ testAware1.test(); test.test(); } } 复制代码
原型 Bean:
@Service @Scope("prototype") public class Test { public void test(){ System.out.println("Test ->" + this); } } 复制代码
注意,知识点来了:如果一个单例的 Bean 依赖了一个原型的 Bean,那么依赖的这个 Bean 是单例的还是原型的?如果是单例的,那么怎么才能拿到原型的?
答案:其实 Spring 在准备环境的时候,会实例化所有的(除去懒加载) Bean,然后缓存起来(还记得 Spring 当中的三个 Map 吗?),在 getBean() 的时候如果发现缓存中已经有了,就会直接拿到不会创建了。因此,如果不做特殊处理的话,单例 Bean 中依赖原型的 Bean 拿到的也是同一个 Bean。那么问题来了,这个有解决方法吗?自然是有的,但是为了不偏离本文的侧重点,这里只给出方案,不做原理上的深究。其实解决这个问题,可以通过以下三种途径来解决:
- 通过上述的 ApplicationContextAware。实现该接口,拿到 ApplicationContext,然后通过 getBean() 获取对象,然后再使用。
- 在原型 Bean 中注入 ApplicationContext,然后通过 getBean() 获取对象,然后再使用。 @Service @Scope(“prototype”) public class Test { @Autowired ApplicationContext applicationContext; public void test(){ System.out.println(“Test ->” + applicationContext.getBean(“test”)); } } 复制代码
- 使用@Lookup注解。 Service @Scope(“prototype”) public abstract class Test1 { @Lookup protected abstract Test1 methodInject(); public void test(){ Test1 test1 = methodInject(); System.out.println(“Test ->” + test1); } } 复制代码 运行结果:
2. applyBeanPostProcessorsBeforeInitialization 方法的执行
欢迎大家来到IT世界,在知识的湖畔探索吧!public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; } 复制代码容器初始化之前做最后的检查,检查 BeanPostProcessor 对 Bean做相应的处理。
3. 激活用户自定义的 init 方法
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { / 首先检查是否是 InitializingBean,如果是的话需要调用afterPropertiesSet方法*/ boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 属性 初始化后的处理,调用 afterPropertiesSet()方法 ((InitializingBean) bean).afterPropertiesSet(); } } / * 从代码看出: * afterPropertiesSet() 和 init-method() 都是在初始化bean时执行, * 执行顺序是 先 afterPropertiesSet()方法执行, * 然后 init-method() 方法执行 */ if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // 调用自定义的初始化方法 invokeCustomInitMethod(beanName, bean, mbd); } } } 复制代码
这里是处理实现了 InitializingBean 接口,被重写了的 afterPropertiesSet() 方法;以及 init-method() 方法的处理。通过下面的 invokeCustomInitMethod() 方法对 @Bean 中的 initMethod 属性或 xml 中 init-Method 进行相应的处理。
欢迎大家来到IT世界,在知识的湖畔探索吧!protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { / * 获取 Bean 定义的 @Bean 中的 initMethod 属性 或xml中init-Method */ String initMethodName = mbd.getInitMethodName(); Assert.state(initMethodName != null, "No init method set"); Method initMethod = (mbd.isNonPublicAccessAllowed() ? BeanUtils.findMethod(bean.getClass(), initMethodName) : ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName)); if (initMethod == null) { if (mbd.isEnforceInitMethod()) { throw new BeanDefinitionValidationException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'"); } else { if (logger.isTraceEnabled()) { logger.trace("No default init method named '" + initMethodName + "' found on bean with name '" + beanName + "'"); } // Ignore non-existent default lifecycle methods. return; } } if (logger.isTraceEnabled()) { logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'"); } Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod); if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(methodToInvoke); return null; }); try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> methodToInvoke.invoke(bean), getAccessControlContext()); } catch (PrivilegedActionException pae) { InvocationTargetException ex = (InvocationTargetException) pae.getException(); throw ex.getTargetException(); } } else { try { ReflectionUtils.makeAccessible(methodToInvoke); / * 通过 JDk 的反射机制得到 Method 对象 * 直接调用在 Bean 中定义声明的初始化方法 */ methodToInvoke.invoke(bean); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } 复制代码
4. applyBeanPostProcessorsAfterInitialization
这里就是对 BeanPostProcessor 中的另一个方法的处理过程。之前的文章多次提到过,这里就不再赘述了。
5. 总结
这篇文章中分析了依赖关系处理完成之后,Bean的初始化的过程,通过上述的4个方面做了简单的分析。从中也了解了Spring中设计的 Aware 接口,通过一道面试题分析简单的使用了一下 ApplicationContextAware。
其实到这里,doCreateBean() 方法已经分析完了,在这个方法中主要完成了以下几件事情 ①:如果是单例首先需要清除缓存;②:实例化 bean,将 BeanDefinition 转化为 BeanWrapper ;③:
MergedBeanDefinitionPostProcessor 的应用;④:依赖处理;⑤:属性填充;⑥:循环依赖处理;⑦:注册 DisposableBean;⑧:完成创建并返回。也就是说 Bean 的创建完成了。
其实到这里,doCreateBean() 方法完成之后,doGetBean() 方法中的流程也已经基本完成了,最后剩了一个 类型转换,程序运行到这里bean的初始化基本结束,requiredType 通常是为空的,但是可能存在这样的情况,返回的 Bean 是个 String,但是 requiredType 是 Integer ,这个时候这个步骤就起作用了:将返回的 Bean 转换为 requiredType 所指定的类型。
关于 doGetBean() 我会在后面的文章中,做一个详细的总结。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/121609.html