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

原文出自:http://cmsblogs.com


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

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {        if (System.getSecurityManager() != null) {            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {                // 激活 Aware 方法                invokeAwareMethods(beanName, bean);                return null;            }, getAccessControlContext());        }        else {            // 对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware            invokeAwareMethods(beanName, bean);        }        Object wrappedBean = bean;        if (mbd == null || !mbd.isSynthetic()) {            // 后处理器            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()) {            // 后处理器            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);        }        return wrappedBean;    }

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

  1. 激活 Aware 方法
  2. 后置处理器的应用
  3. 激活自定义的 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() 源码如下:

    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);            }        }    }

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

后置处理器的应用

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

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

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)            throws BeansException {        Object result = existingBean;        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {            Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);            if (current == null) {                return result;            }            result = current;        }        return result;    }    @Override    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)            throws BeansException {        Object result = existingBean;        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {            Object current = beanProcessor.postProcessAfterInitialization(result, beanName);            if (current == null) {                return result;            }            result = current;        }        return result;    }

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

激活自定义的 init 方法

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

   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.isDebugEnabled()) {                logger.debug("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 {                // 属性初始化的处理                ((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)) {                // 激活用户自定义的 初始化方法                invokeCustomInitMethod(beanName, bean, mbd);            }        }    }

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

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

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

原文发布于微信公众号 - Java技术驿站(chenssy89)

原文发表时间:2018-11-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏石奈子的Java之路

原 SpringBoot 2.0 系列00

15240
来自专栏微信公众号:Java团长

Spring Boot 自动配置的“魔法”是如何实现的?

Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

14620
来自专栏battcn

Spring解密 - 默认标签的解析

紧跟上篇 Spring解密 - XML解析 与 Bean注册 ,我们接着往下分析源码

11610
来自专栏不会写文章的程序员不是好厨师

Spring源码初探-IOC(5)-ApplicationContext功能扩展及其扩展点

前面几篇关于Spring的文章简单阐述了使用BeanFactory作为容器时bean的初始化过程。然而在实际使用中,我们并不会直接接触和编码BeanFactor...

13020
来自专栏java工会

Spring Boot 自动配置的 “魔法” 是如何实现的?

Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

9300
来自专栏精讲JAVA

Spring Boot 自动配置的 “魔法” 是如何实现的?

Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快...

12320
来自专栏我叫刘半仙

原向Spring大佬低头--大量源码流出解析

       用Spring框架做了几年的开发,只停留在会用的阶段上,然而Spring的设计思想和原理确实一个巨大的宝库。大部分人仅仅知道怎么去配,或着加上什么...

45560
来自专栏向治洪

深入理解Android Instant Run运行机制

Instant Run Instant Run,是android studio2.0新增的一个运行机制,在你编码开发、测试或debug的时候,它都能显著减少你对...

1.8K100
来自专栏zhisheng

看透 Spring MVC 源代码分析与实践 —— Spring MVC 组件分析

组件概览 HandlerMapping 根据 request 找到对应的处理器 Handler 和 Interceptors。内部只有一个方法 Handler...

29980
来自专栏技术小黑屋

如何在Android中避免创建不必要的对象

在编程开发中,内存的占用是我们经常要面对的现实,通常的内存调优的方向就是尽量减少内存的占用。这其中避免创建不必要的对象是一项重要的方面。

8120

扫码关注云+社区

领取腾讯云代金券