【死磕 Spring】—– IOC 之 bean 的初始化

简介:

一个 bean 经历了 createBeanInstance() 被创建出来,然后又经过一番属性注入,依赖处理,历经千辛万苦,千锤百炼,终于有点儿 bean 实例的样子,能堪大任了,只需要经历最后一步就破茧成蝶了。这最后一步就是初始化,也就是 initializeBean(),所以这篇文章我们分析 doCreateBean() 中最后一步:初始化 bean。

 
  1. protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

  2. if (System.getSecurityManager() != null) {

  3. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {

  4. // 激活 Aware 方法

  5. invokeAwareMethods(beanName, bean);

  6. return null;

  7. }, getAccessControlContext());

  8. }

  9. else {

  10. // 对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware

  11. invokeAwareMethods(beanName, bean);

  12. }


  13. Object wrappedBean = bean;

  14. if (mbd == null || !mbd.isSynthetic()) {

  15. // 后处理器

  16. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

  17. }


  18. try {

  19. // 激活用户自定义的 init 方法

  20. invokeInitMethods(beanName, wrappedBean, mbd);

  21. }

  22. catch (Throwable ex) {

  23. throw new BeanCreationException(

  24. (mbd != null ? mbd.getResourceDescription() : null),

  25. beanName, "Invocation of init method failed", ex);

  26. }

  27. if (mbd == null || !mbd.isSynthetic()) {

  28. // 后处理器

  29. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

  30. }

  31. return wrappedBean;

  32. }

初始化 bean 的方法其实就是三个步骤的处理,而这三个步骤主要还是根据用户设定的来进行初始化,这三个过程为:

激活 Aware 方法

后置处理器的应用

激活自定义的 init 方法

激活 Aware 方法

Aware ,英文翻译是意识到的,感知的,Spring 提供了诸多 **Aware 接口用于辅助 Spring Bean 以编程的方式调用 Spring 容器,通过实现这些接口,可以增强 Spring Bean 的功能。

Spring 提供了如下系列的 Aware 接口:

  • LoadTimeWeaverAware:加载Spring Bean时织入第三方模块,如AspectJ

  • BeanClassLoaderAware:加载Spring Bean的类加载器

  • BootstrapContextAware:资源适配器BootstrapContext,如JCA,CCI

  • ResourceLoaderAware:底层访问资源的加载器

  • BeanFactoryAware:声明BeanFactory

  • PortletConfigAware:PortletConfig

  • PortletContextAware:PortletContext

  • ServletConfigAware:ServletConfig

  • ServletContextAware:ServletContext

  • MessageSourceAware:国际化

  • ApplicationEventPublisherAware:应用事件

  • NotificationPublisherAware:JMX通知

  • BeanNameAware:声明Spring Bean的名字

invokeAwareMethods() 源码如下:

 
  1. private void invokeAwareMethods(final String beanName, final Object bean) {

  2. if (bean instanceof Aware) {

  3. if (bean instanceof BeanNameAware) {

  4. ((BeanNameAware) bean).setBeanName(beanName);

  5. }

  6. if (bean instanceof BeanClassLoaderAware) {

  7. ClassLoader bcl = getBeanClassLoader();

  8. if (bcl != null) {

  9. ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);

  10. }

  11. }

  12. if (bean instanceof BeanFactoryAware) {

  13. ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);

  14. }

  15. }

  16. }

这里代码就没有什么好说的,主要是处理 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。关于 Aware 接口,后面会专门出篇文章对其进行详细分析说明的。

后置处理器的应用

BeanPostProcessor 在前面介绍 bean 加载的过程曾多次遇到,相信各位不陌生,这是 Spring 中开放式框架中必不可少的一个亮点。

BeanPostProcessor 的作用是:如果我们想要在 Spring 容器完成 Bean 的实例化,配置和其他的初始化后添加一些自己的逻辑处理,那么请使用该接口,这个接口给与了用户充足的权限去更改或者扩展 Spring,是我们对 Spring 进行扩展和增强处理一个必不可少的接口。

 
  1. public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)

  2. throws BeansException {


  3. Object result = existingBean;

  4. for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {

  5. Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);

  6. if (current == null) {

  7. return result;

  8. }

  9. result = current;

  10. }

  11. return result;

  12. }


  13. @Override

  14. public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)

  15. throws BeansException {


  16. Object result = existingBean;

  17. for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {

  18. Object current = beanProcessor.postProcessAfterInitialization(result, beanName);

  19. if (current == null) {

  20. return result;

  21. }

  22. result = current;

  23. }

  24. return result;

  25. }

其实逻辑就是通过 getBeanPostProcessors() 获取定义的 BeanPostProcessor ,然后分别调用其 postProcessBeforeInitialization()postProcessAfterInitialization() 进行业务处理。

激活自定义的 init 方法

如果熟悉 <bean> 标签的配置,一定不会忘记 init-method 方法,该方法的执行就是在这里执行的。

 
  1. protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)

  2. throws Throwable {

  3. // 首先会检查是否是 InitializingBean ,如果是的话需要调用 afterPropertiesSet()

  4. boolean isInitializingBean = (bean instanceof InitializingBean);

  5. if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {

  6. if (logger.isDebugEnabled()) {

  7. logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");

  8. }

  9. if (System.getSecurityManager() != null) {

  10. try {

  11. AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {

  12. ((InitializingBean) bean).afterPropertiesSet();

  13. return null;

  14. }, getAccessControlContext());

  15. }

  16. catch (PrivilegedActionException pae) {

  17. throw pae.getException();

  18. }

  19. }

  20. else {

  21. // 属性初始化的处理

  22. ((InitializingBean) bean).afterPropertiesSet();

  23. }

  24. }


  25. if (mbd != null && bean.getClass() != NullBean.class) {

  26. String initMethodName = mbd.getInitMethodName();

  27. if (StringUtils.hasLength(initMethodName) &&

  28. !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&

  29. !mbd.isExternallyManagedInitMethod(initMethodName)) {

  30. // 激活用户自定义的 初始化方法

  31. invokeCustomInitMethod(beanName, bean, mbd);

  32. }

  33. }

  34. }

首先检查是否为 InitializingBean ,如果是的话需要执行 afterPropertiesSet(),因为我们除了可以使用 init-method 来自定初始化方法外,还可以实现 InitializingBean 接口,该接口仅有一个 afterPr9opertiesSet() 方法,而两者的执行先后顺序是先 afterPropertiesSet()init-method

关于这篇博客的三个问题,LZ 后面会单独写博客来进行分析说明。

经过六篇博客终于把 Spring 创建 bean 的过程进行详细说明了,过程是艰辛的,但是收获很大,关键还是要耐着性子看。


原文发布时间为: 2018-11-19
本文作者: Java技术驿站
本文来自云栖社区合作伙伴“ Java技术驿站”,了解相关信息可以关注“Java技术驿站”。

相关文章
|
24天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
32 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
61 0
|
1天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
9天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
17 1
|
13天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
19 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
22天前
|
XML Java 数据格式
Spring(一)IOC小案例
Spring(一)IOC小案例
|
24天前
|
XML Java 程序员
作为Java程序员还不知道Spring中Bean创建过程和作用?
作为Java程序员还不知道Spring中Bean创建过程和作用?
14 0
|
28天前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
17 0
|
1月前
|
Java Spring
Spring5深入浅出篇:bean的生命周期
Spring5深入浅出篇:bean的生命周期
|
1月前
|
XML Java 数据格式
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (下)
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界