zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/leisurexi/p/13238055.html
Copyright © 2011-2022 走看看