• Spring IoC bean 的初始化


    前言

    本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。

    本篇文章主要介绍 Spring IoC 容器中 bean 的初始化阶段。

    正文

    我们在Spring IoC bean 的创建一文中分析创建 bean 实例的主要流程,此时创建出来的 bean 还是个属性未赋值的实例,在创建完之后会进入 populateBean() 方法,即进入属性赋值阶段。我们简单回顾一下,上次分析过的 doCreateBean() 方法:

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
    
        // 实例化 bean
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // 如果bean的作用域是singleton,则需要移除未完成的FactoryBean实例的缓存
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 通过构造函数反射创建bean的实例,但是属性并未赋值,见下文详解
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // 获取bean的实例
        final Object bean = instanceWrapper.getWrappedInstance(); 
        // 获取bean的类型
        Class<?> beanType = instanceWrapper.getWrappedClass(); 
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
    
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    // BeanDefinition 合并后的回调,见下文详解
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } 
                // 省略异常处理...
                mbd.postProcessed = true;
            }
        }
    
        // bean的作用域是单例 && 允许循环引用 && 当前bean正在创建中
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
        // 如果允许bean提前曝光
        if (earlySingletonExposure) {
            // 将beanName和ObjectFactory形成的key-value对放入singletonFactories缓存中
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
    
        Object exposedObject = bean;
        try {
            // 给 bean 的属性赋值
            populateBean(beanName, mbd, instanceWrapper);
            // 初始化 bean
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        } 
        // 省略部分代码
    }
    

    上篇文章分析了 populateBean() 方法,这次我们总店分析 initializeBean() 方法。

    bean 的初始化

    AbstractAutoCapableBeanFactory#initializeBean

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    
        // BeanAware的接口回调,见下文详解
        invokeAwareMethods(beanName, bean);
    
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor的postProcessBeforeInitialization()回调,也就是bean初始化前的回调
            // 在 ApplicationContextAwareProcessor实现的postProcessBeforeInitialization方法中会执行
            // ApplicationContext Aware的接口回调。
            // InitDestoryAnnotationBeanPostProcessor的postProcessBeforeInitialization()中会执行
            // 标注了@PostConstruct注解的方法。
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
    
        try {
            // 调用bean的自定义初始化方法,如afterPropertiesSet,XML中的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()) {
            // BeanPostProcessor的postProcessAfterInitialization()回调,也就是bean初始化后的回调
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
    
        return wrappedBean;
    }
    

    Aware 接口回调

    AbstractAutowireCapableBeanFactory#invokeAwareMethods

    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            // BeanNameAware接口方法回调
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            // BeanClassLoaderAware接口方法回调
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            // BeanFactoryAware接口方法回调
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }
    

    通过实现这些 Aware 接口的 bean 的被初始化之前,可以取得一些相对应的资源,比如 beanNamebeanFactory 等。

    bean 的初始化前回调

    AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
    
        Object result = existingBean;
        // 遍历所有注册的BeanPostProcessor实现类,调用postProcessBeforeInitialization方法
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 在bean初始化方法执行前,调用postProcessBeforeInitialization方法
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
    

    上面方法主要是调用了 BeanPostProcessorpostProcessBeforeInitialization() 方法,下面我们看一下 BeanPostProcessor 接口的定义:

    public interface BeanPostProcessor {
    
        /**
         * bean初始化前调用,此时bean已经实例化并且属性已经赋值,Aware接口已经回调;返回非 {@code null} 会使用返回的bean
         */
        @Nullable
        default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        /**
         * bean初始化后调用,返回非 {@code null} 会使用返回的bean
         */
        @Nullable
        default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
    }
    

    调用初始化方法

    AbstractAutowireCapableBeanFactory#invokeInitMethods

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    
        // bean是否实现InitializingBean接口
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            // 调用afterPropertiesSet方法
            ((InitializingBean) bean).afterPropertiesSet();
        }
    
        // 调用自定义的init方法,例如XML中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);
            }
        }
    }
    

    我们知道设置 bean 的初始化方法其实有三种方式 @PostConstructInitializingBean、自定义初始化方法,一个 bean 同时实现这三种方式时,调用顺序如下:

    1. @PostConstruct
    2. InitializingBean#afterPropertiesSet()
    3. 自定义初始化方法

    从上面方法可以很容易的看出 InitializingBean 接口的 afterPropertiesSet() 方法先于自定义初始化方法调用,那么 @PostConstruct 注解标注的方法在何时调用的呢?玄机就在上面介绍的 BeanPostProcessor 接口,InitDestroyAnnotationBeanPostProcessor 实现了该接口并重写了 postProcessBeforeInitialization() 方法调用了标注 @PostConstruct 注解的方法。我会在后续文章分析其实现。

    bean 初始化后回调

    AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
    
        Object result = existingBean;
        // 遍历所有注册的BeanPostProcessor实现类,调用postProcessAfterInitialization方法
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 在bean初始化方法执行后,调用postProcessBeforeInitialization方法
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
    

    总结

    本篇文章主要分析了 Spring IoC bean 的初始化阶段流程,Spring 在此阶段也提供了2个扩展点;分别是 bean 的初始化前和初始化后,也就是 BeanPostProcessor 接口,该接口十分重要其它 processor 接口都是直接或间接在此接口上扩展出来的。

    最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址:https://github.com/leisurexi/tiny-spring

  • 相关阅读:
    《Unix/Linux系统编程》第十二章学习笔记
    《Unix/Linux系统编程》第十四章学习笔记
    实验三电子公文传输系统1个人贡献
    js模版引擎(基于html模版和json数据的javascript交互)(第一讲)
    asp.net之反射
    JQuery 插件之Ajax Autocomplete(ajax自动完成)
    js模版引擎(基于html模版和json数据的javascript交互)(第二讲)完结篇
    在Sharepoint项目中究竟应该做哪类的开发?
    MVP Open day随想
    从瘦客户端到RIA
  • 原文地址:https://www.cnblogs.com/leisurexi/p/13238055.html
Copyright © 2020-2023  润新知