逐行解读Spring(四) - 万字长文讲透bean生命周期(上)

7,073 阅读30分钟

创作不易,转载请篇首注明 作者:掘金@小希子 + 来源链接~

如果想了解更多Spring源码知识,点击前往其余逐行解析Spring系列

一、前言

这些天一直在琢磨bean生命周期这一块应该怎么写,因为这一块的流程实在比较长,而且涉及到很多beanPostProcessor的埋点,很多我们常见的功能都是通过这些埋点来做的。

最终,我决定先用一篇博文,把bean生命周期的主流程较为**粗略(相对)**的讲一下。之后,会通过一系列博文对主流程中的一些细节、和一些常见的功能是怎么通过spring预留的beanPostProcessor埋点来实现的。感兴趣的同学可以自己选择查看。

(由于掘金对文章字数的限制,这篇博文被迫分为上下两篇,点击前往下一篇

二、Spring容器的启动

发现其实到现在,我的这一系列spring博文,都没有好好讲过spring容器启动的过程(第一篇中也是直接给定位到了refresh方法)。正好上一篇讲的纯注解启动类AnnotationConfigApplicationContext,这里我们再回顾一下:

@Test
public void test() {
    // 我们平常使用AnnotationConfigApplicationContext的时候,只需要这样直接new出来就好了
    applicationContext = new AnnotationConfigApplicationContext("com.xiaoxizi.spring");
    // 然后就可以从容器中拿到bean对象了,说明其实new创建对象的时候,我们容器就做好启动初始化工作了~
    MyAnnoClass myAnnoClass = applicationContext.getBean(MyAnnoClass.class);
    System.out.println(myAnnoClass);
}

// AnnotationConfigApplicationContext的构造器
public AnnotationConfigApplicationContext(String... basePackages) {
    this();
    // 扫描目标包,收集并注册beanDefinition,上一篇具体讲过,这里就不赘述了
    scan(basePackages);
    // 这里就调用到我们大名鼎鼎的refresh方法啦
    refresh();
}

我们看一下这个容器启动的核心方法refresh,这个方法的逻辑是在AbstractApplicationContext类中的,也是一个典型的模板方法:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 一些准备工作,主要是一下状态的设置事件容器的初始化
        prepareRefresh();

        // 获取一个beanFactory,这个方法里面调用了一个抽象的refreshBeanFactory方法
        // 我们的xml就是在这个入口里解析的,具体的流程有在之前的博文分析过
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 把拿到的beanFactory做一些准备,这里其实没啥逻辑,同学们感兴趣的可以看下
        // 但是这个方法也是一个protected的方法,
        // 也就是说我们如果实现自己的spring启动类/或者spring团队需要写一个新的spring启动类的时候
        // 是可以在beanFactory获取之后做一些事情的,算是一个钩子
        prepareBeanFactory(beanFactory);
		
        try {
            // 这也是一个钩子,在处理beanFactory前允许子类做一些事情
            postProcessBeanFactory(beanFactory);

            // 实例化并且调用factoryPostProcessor的方法,
            // 我们@Compoment等注解的收集处理主要就是在这里做的
            // 有一个ConfigurationClassPostProcessor专门用来做这些注解支撑的工作
          	// 这里的逻辑之前也讲过了
            // 那么其实我们可以说,到这里为止,我们的beanDefinition的收集(注解/xml/其他来源...)
            // 、注册(注册到beanFactory的beanDefinitionMap、beanDefinitionNames)容器
            // 工作基本就全部完成了
            invokeBeanFactoryPostProcessors(beanFactory);
			
            // 从这里开始,我们就要专注bean的实例化了
            // 所以我们需要先实例化并注册所有的beanPostProcessor
            // 因为beanPostProcessor主要就是在bean实例化过程中,做一些附加操作的(埋点)
            // 这里的流程也不再讲了,感兴趣的同学可以自己看一下,
            // 这个流程基本跟FactoryPostProcessor的初始化是一样的,
            // 排序,创建实例,然后放入一个list --> AbstractBeanFactory#beanPostProcessors
            registerBeanPostProcessors(beanFactory);

            // 初始化一些国际化相关的组件,这一块我没有去详细了解过(主要是暂时用不到...)
            // 之后如果有时间也可以单独拉个博文来讲吧
            initMessageSource();

            // 初始化事件多播器,本篇不讲
            initApplicationEventMulticaster();

            // 也是个钩子方法,给子类创建一下特殊的bean
            onRefresh();

            // 注册事件监听器,本篇不讲
            registerListeners();

            // !!!实例化所有的、非懒加载的单例bean
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // 初始化结束,清理资源,发送事件
            finishRefresh();
        }
        catch (BeansException ex) {
            // 销毁已经注册的单例bean
            destroyBeans();
            // 修改容器状态
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

其实说白了,我们spring容器的启动,主要就是要把那些非懒加载的单例bean给实例化,并且管理起来。

三、bean实例化

1. 哪些bean需要在启动的时候实例化?

刚刚refresh方法中,我们有看到finishBeanFactoryInitialization方法是用来实例化bean的,并且源码中的英文也说明了,说是要实例化所以剩余的非懒加载的单例bean,那么实际情况真的如此么?我们跟源码看一下:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// skip .. 我把前面的非主流程的跳过了
    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
}

// DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
    // 我们之前注册beanDefinition的时候,有把所有的beanName收集到这个beanDefinitionNames容器
    // 这里我们就用到了
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // 循环所有的已注册的beanName
    for (String beanName : beanNames) {
        // 获取合并后的beanDefinition,简单来讲,我们的beanDefinition是可以存在继承关系的
        // 比如xml配置从的parent属性,这种时候,我们需要结合父子beanDefinition的属性,生成一个新的
        // 合并的beanDefinition,子beanDefinition中的属性会覆盖父beanDefinition的属性,
        // 并且这是一个递归的过程(父还可以有父),不过这个功能用的实在不多,就不展开了,
        // 同学们有兴趣可以自行看一下,这里可以就理解为拿到对应的beanDefinition就好了
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 非抽象(xml有一个abstract属性,而不是说这个类不是一个抽象类)、单例的、非懒加载的才需要实例化
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                // 这里是处理factoryBean的,暂时不讲,之后再专门写博文
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                                                    ((SmartFactoryBean<?>) factory)::isEagerInit,
                                                                    getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                // !!!我们正常普通的bean会走到这个流程,这里就把这个bean实例化并且管理起来的
                // 这里是获取一个bean,如果获取不到,则创建一个
                getBean(beanName);
            }
        }
    }

    // 所以的bean实例化之后,还会有一些处理
    for (String beanName : beanNames) {
        // 获取到这个bean实例
        Object singletonInstance = getSingleton(beanName);
        // 如果bean实现了SmartInitializingSingleton接口
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            // 会调用它的afterSingletonsInstantiated方法
            // 这是最外层的一个钩子了,平常其实用的不多
            // 不过@Listener的发现是在这里做的
            smartSingleton.afterSingletonsInstantiated();
        }
    }
}

可以看到,原来是非抽象xml有一个abstract属性,而不是说这个类不是一个抽象类)、单例的非懒加载bean才会在spring容器启动的时候实例化,spring老哥们,你们的注释打错了呀(抠一下字眼就很开心)~

2. 使用getBeanbeanFactory获取bean

刚刚有说到,调用getBean方法的时候,会先尝试中spring容器中获取这个bean,获取不到的时候则会创建一个,现在我们就来梳理一下这个流程:

public Object getBean(String name) throws BeansException {
    // 调用了doGetBean
    // 说一下这种方式吧,其实我们能在很多框架代码里看到这种方式
    // 就是会有一个参数最全的,可以最灵活使用的方法,用来处理我们的业务
    // 然后会对不同的使用方,提供一些便于使用的类似于门面的方法,这些方法会简化一些参数,使用默认值填充
    // 或者实际业务可以很灵活,但是不打算完全开放给使用方的时候,也可以使用类似的模式
    return doGetBean(name, null, null, false);
}

getBean->doGetBean是我们beanFactory对外提供的获取bean的接口,只是说我们初始化spring容器的时候会为所有单例的beanDefinition调用getBean方法实例化它们定义的bean而已,所以它的的逻辑并不仅仅是为spring容器初始化定义的,我们也需要带着这个思维去看这个方法:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	// 转换一下beanName,暂时不看,之后统一讲
    final String beanName = transformedBeanName(name);
    Object bean;

    // 看一下这个bean是否已经实例化了,如果实例化了这里能直接拿到
    // 这个方法涉及到spring bean的3级缓存,之后会开一篇博客细讲
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 通过这个bean实例获取用户真正需要的bean实例
        // 有点绕,其实这里主要是处理当前bean实现了FactoryBean接口的情况的
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        // 当前线程下的,循环依赖检测,如果当前bean已经在创建中,这里又进来创建了,说明是循环依赖了
        // 会直接报错,代码逻辑也很简单,这里主要是一个TheadLocal持有了一个set,
        // 可以认为是一个快速失败检测,和后面的全局循环依赖检测不是一个容器
        // 容器是 prototypesCurrentlyInCreation
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }


        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 如果父容器不为空且当前容器没有这个beanName对应的beanDefinition
            // 则尝试从父容器获取(因为当期容器已经确定没有了)
            // 下面就是调用父容器的getBean了
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }
		// 如果不是只检测类型是否匹配的话,这里要标记bean已创建(因为马上就要开始创建了)
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);
			// 拿到这个bean的所有依赖的bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                // 如果依赖不为空,需要先循环实例化依赖
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(...);
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(...);
                    }
                }
            }

            // 这里开始真正创建bean实例的流程了
            if (mbd.isSingleton()) {
                // 如果是单例的bean(当然我们启动的时候会实例化的也就是单例bean了),这里会进行创建
                // 注意这里也是一个getSingleton方法,跟之前那个getSingleton方法差不多,不过这里是
                // 如果获取不到就会使用这个lamdba的逻辑创建一个,
                // 也就是说我的的createBean方法是真正创建bean实例的方法,这里我们之后会重点看
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                // 通过这个bean实例获取用户真正需要的bean实例
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            else if (mbd.isPrototype()) {
                // 如果是多例的bean
                // 那么每次获取都是创建一个新的bean实例
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    // 可以看到这里直接去调用createBean了
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                // 这里逻辑还是一样的
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            else {
                // spring是允许我们自定义scope的,这里是自定义scope的逻辑
                // 需要注意的是,spring mvc 的 session、request那些scope也是走这里的逻辑的
                // 这里感兴趣的同学可以自行看下,暂时不讲
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException(...);
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(...);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
	
    // 这里是类型转换的逻辑,getBean是有可以传类型的重载方法的
    // 不过我们初始化的时候不会走到这个逻辑来,感兴趣的同学可以自行看
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(...);
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            throw new BeanNotOfRequiredTypeException(...);
        }
    }
    // 返回获取到的bean
    return (T) bean;
}

我们继续看一下单例bean的创建逻辑,即:

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // ...
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

我们看一下这个getSingleton方法,需要注意的是,这个方法在DefaultSingletonBeanRegistry类中:

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        // 可以看到,我们先从singletonObjects通过beanName获取实例
		// 这是不是说明singletonObjects就是spring用来存放所以单例bean的容器呢?可以说是的。
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
			// 跳过了一个spring单例bean容器状态判断,
            // 如果spring单例bean容器正在销毁时不允许继续创建单例bean的
            
            // 创建容器之前的钩子,这里默认会把bean那么加入到一个正在创建的beanNameSet,
            // 如果加入失败就代表是循环依赖了。
            // 检测容器是  singletonsCurrentlyInCreation
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 这里就是调用传进来的lamdba了
                // 也就是调用了createBean创建了bean实例
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // 从正在创建的beanNameSet移除
                afterSingletonCreation(beanName);
            }
            // 如果成功创建了bean实例,需要加入singletonObjects容器
            // 这样下次再获取就能直接中容器中拿了
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

可以看到,这个getSingleton方法就是先从singletonObjects获取bean实例,获取不到就创建一个,其中还加了一些循环依赖的检测逻辑。

3. createBean,真正的bean初始化逻辑

我们说createBean方法是真正的bean初始化逻辑,但是这个初始化不仅仅是说创建一个实例就好了,还涉及到一些校验,以及类里的依赖注入、初始化方法调用等逻辑,我们现在就一起来简单看一下:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
	
    RootBeanDefinition mbdToUse = mbd;
    // 获取bean的类型
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
	
    // Prepare method overrides.
    try {
        // 这里对beanDefinition中的MethodOverrides做一些准备
        // 主要是梳理一下所有重写方法(xml<replaced-method><lockup-method>标签对应的属性)
        // 看下这些方法是否是真的有重载方法,没有重载的话会设置overloaded=false,
        // 毕竟有些人配置的时候即使没有重载方法也会使用<replaced-method>标签
        // (这功能我确实也没用过。。
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(...);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        // 给BeanPostProcessors一个机会,在我们的bean实例化之前返回一个代理对象,即完全不走spring的实例化逻辑
        // 也是个BeanPostProcessors的钩子,就是循环beanPostProcessors然后调用的逻辑
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(...);
    }

    try {
        // 这里是spring真正bean实例化的地方了
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        // 获取到了直接返回
        return beanInstance;
    }
    // 跳过异常处理
}

3.0. doCreateBean是如何实例化一个bean的?

刚刚有说到,doCreateBean是我们spring真正的实例化bean的逻辑,那我们一起来看一下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 创建bean实例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // 调用一个BeanPostProcessor的钩子方法,这里调用的是
                // MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
                // 这个钩子方法是在bean实例创建之后,依赖注入之前调用的,需要注意的是
                // @Autowired和@Value注解的信息收集-AutowiredAnnotationBeanPostProcessor
                // @PostConstruct、@PreDestroy注解信息收集-CommonAnnotationBeanPostProcessor
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(...);
            }
            mbd.postProcessed = true;
        }
    }

   	// 这一部分是使用3级缓存来解决循环依赖问题的,之后再看
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        // 加入三级缓存
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    
    Object exposedObject = bean;
    try {
        // 依赖注入
        populateBean(beanName, mbd, instanceWrapper);
        // bean初始化-主要是调用一下初始化方法
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            throw new BeanCreationException(...);
        }
    }
	// 这里也算是循环依赖检测的,暂时不讲
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(...);
                }
            }
        }
    }
    try {
        // 如果是单例bean,还会注册销毁事件
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(...);
    }

    return exposedObject;
}

可以看到,我们的doCreateBean大致做了5件事:

  1. 创建bean实例
  2. 调用beanPostProcessor的埋点方法
  3. 注入当前类依赖的bean
  4. 调用当前bean的初始化方法
  5. 注册当前bean的销毁逻辑

接下来我们来详细看一下这些流程

3.1. createBeanInstance创建bean实例

大家平常是怎么实例化一个类呢?是直接使用构造器new出来一个?还是使用工厂方法获取?

很显然,spring也是支持这两种方式的,如果同学们还记得bean标签的解析的话,那应该还会记得spring除了有提供使用构造器实例化beanconstructor-arg标签外,还提供了factory-beanfactory-method属性来配置使用工厂方法来实例化bean

并且之前在讲ConfigurationClassPostProcessor的时候,我们讲到@bean标签的时候,也有看到,对于@bean标签的处理,就是新建一个beanDefinition,并把当前的配置类和@Bean修饰的方法分别塞入了这个beanDefinitionfactoryBeanNamefactoryMethodName属性(可以空降ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod)。

接下来我们就来看一下createBeanInstance的代码:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
	// 校验
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }
	// 如果beanDefinition里有instanceSupplier,直接通过instanceSupplier拿就行了
    // 这种情况我们就不重点讲了,其实跟工厂方法的方式也差不多
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    
	// 如果工厂方法不为空,就使用工厂方法实例化
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 这里是对非单例bean做的优化,如果创建过一次了,
    // spring会把相应的构造器或者工厂方法存到resolvedConstructorOrFactoryMethod字段
    // 这样再次创建这个类的实例的时候就可以直接使用resolvedConstructorOrFactoryMethod创建了
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }

    // 如果beanDefinition没有构造器信息,则通过beanPostProcessor选择一个
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    // 1.如果通过beanPostProcessor找到了合适的构造器
    // 2.或者autowireMode==AUTOWIRE_CONSTRUCTOR(这个xml配置的时候也可以指定的)
    // 3.或者有配置构造器的参数(xml配置constructor-arg标签)
    // 4.获取实例化bean是直接传进来了参数
    // 只要符合上面四种情况之一,我们就会通过autowireConstructor方法来实例化这个bean
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        // 需要构造器方式注入的bean的实例化
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 这里主要逻辑是兼容kotlin的,我们暂时不看
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        // 需要构造器方式注入的bean的实例化
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // 不需要特殊处理的话,就直接使用无参构造器了
    return instantiateBean(beanName, mbd);
}

具体的instantiateUsingFactoryMethodautowireConstructo方法这边就不带同学们看了,因为里面涉及到的一些参数注入的逻辑比较复杂,之后会单独开一篇博客来讲。

而拿到具体的参数之后,其实不管是构造器还是工厂方法实例化,都是很清晰的,直接反射调用就好了。

instantiateBean就是获取无参构造器然后反射实例化的一个逻辑,逻辑比较简单,这边也不跟了。

3.1.1. 通过determineConstructorsFromBeanPostProcessors方法选择构造器

这边主要带大家跟一下determineConstructorsFromBeanPostProcessors这个方法,因为我们现在大部分都是使用注解来声明bean的,而如果大家在使用注解的时候也是使用构造器的方式注入的话,那么是通过这个方法来拿到相应的构造器的。

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
    throws BeansException {
    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    // 一旦拿到构造器就返回了
                    return ctors;
                }
            }
        }
    }
    return null;
}

可以看到,还是通过beanPostProcessor的埋点来做的,这里是调用的SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors,这里也不给大家卖关子了,我们真正支撑注解方式,选择构造器的逻辑在AutowiredAnnotationBeanPostProcessor中,有没有感觉这个类好像也有点熟悉?

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    // ...
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    // ...
}

也是有在调用AnnotationConfigUtils#registerAnnotationConfigProcessors方法的时候有注入哦~

从名称可以看到,这个beanPostProcessor是应该是用来处理@Autowired注解的,有同学要说了,这不是属性注入的注解么,跟构造器有什么关系?那我们已一个构造器注入的bean来举例:

@Service
public class ConstructorAutowiredBean {
    private Student student;
    @Autowired
    public ConstructorAutowiredBean(Student student) {
        this.student = student;
    }
}

大部分同学可能忘了,@Autowired是可以用来修饰构造器的,被@Autowired修饰的构造器的参数也将会中spring容器中获取(这么说可能不太准确,大家明白我的意思就好,就是说构造器注入的意思...)。

不过,其实我们平常即使使用构造器注入也不打@Autowired注解也是没问题的,这其实也是AutowiredAnnotationBeanPostProcessor获取构造器时的一个容错逻辑,我们一起看一下代码就知道了:

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
    throws BeanCreationException {
	// 整个方法分为了两个部分
    // 第一部分是收集这个类上被@Lookup修饰的方法
    // 这个注解的功能和我们xml的lookup-method标签是一样的
    // 而收集部分也是一样的封装到了一个MethodOverride并且加入到beanDefinition里面去了
    // 虽然这部分工作(@Lookup注解的收集工作)是应该放在bean创建之前(有MethodOverride的话会直接生成代理实例)
    // 但是放在当前这个determineCandidateConstructors方法里我还是觉得不太合适
    // 毕竟跟方法名的语意不符,不过好像确实没有其它合适的钩子了,可能也只能放这了
    if (!this.lookupMethodsChecked.contains(beanName)) {
        if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
            try {
                Class<?> targetClass = beanClass;
                do {
                    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                        // 循环处理所有的方法,获取@Lookup注解并封装信息
                        Lookup lookup = method.getAnnotation(Lookup.class);
                        if (lookup != null) {
                            LookupOverride override = new LookupOverride(method, lookup.value());
                            try {
                                RootBeanDefinition mbd = (RootBeanDefinition)
                                    this.beanFactory.getMergedBeanDefinition(beanName);
                                mbd.getMethodOverrides().addOverride(override);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(...);
                            }
                        }
                    });
                    targetClass = targetClass.getSuperclass();
                }
                while (targetClass != null && targetClass != Object.class);

            }
            catch (IllegalStateException ex) {
                throw new BeanCreationException(...);
            }
        }
        this.lookupMethodsChecked.add(beanName);
    }

    // 这里开始是选择构造器的逻辑了
    // 先从缓存拿...这些也是为非单例bean设计的,这样就不用每次进来都走选择构造器的逻辑了
    Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
    if (candidateConstructors == null) {
        synchronized (this.candidateConstructorsCache) {
            candidateConstructors = this.candidateConstructorsCache.get(beanClass);
            if (candidateConstructors == null) {
                Constructor<?>[] rawCandidates;
                try {
                    // 获取当前类的所有的构造器
                    rawCandidates = beanClass.getDeclaredConstructors();
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(...);
                }
                // 这个列表存符合条件的构造器
                List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                Constructor<?> requiredConstructor = null;
                Constructor<?> defaultConstructor = null;
                // 这个primaryConstructor我们不管,是兼容kotlin的逻辑
                Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                int nonSyntheticConstructors = 0;
                for (Constructor<?> candidate : rawCandidates) {
                    // 循环每个构造器
                    if (!candidate.isSynthetic()) {
                        // 这个判断是判断不是合成的构造器,同学们想了解这个Synthetic可以自行查一下
                        // 这边就不展开了,这个主意是和内部类有关,Synthetic的构造器是编译器自行生成的
                        nonSyntheticConstructors++;
                    }
                    else if (primaryConstructor != null) {
                        continue;
                    }
                    // 找一下构造器上有没有目标注解,说白了就是找@Autowired注解
                    MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                    if (ann == null) {
                       	// 如果找不到,这里认为可能是因为当前这个class是spring生成的cglib代理类
            			// 所以这里尝试拿一下用户的class
                        Class<?> userClass = ClassUtils.getUserClass(beanClass);
                        // 如果用户的class和之前的beanClass不一致,说明之前那个class真的是代理类了
                        if (userClass != beanClass) {
                            try {
                                // 这个时候去userClass拿一下对应的构造器
                                Constructor<?> superCtor =
                                    userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                // 再在用户的构造器上找一下注解
                                ann = findAutowiredAnnotation(superCtor);
                            }
                            catch (NoSuchMethodException ex) {
                            }
                        }
                    }
                    if (ann != null) {
                        // 这里是找到注解了
                        if (requiredConstructor != null) {
                            // 这个分支直接报错了,意思是之前已经如果有被@Autowired注解修饰了的构造器
                            // 且注解中的Required属性为true的时候,
                            // 就不允许再出现其他被@Autowired注解修饰的构造器了
                            // 说明@Autowired(required=true)在构造器上的语言是必须使用这个构造器
                            throw new BeanCreationException(...);
                        }
                        // 拿注解上的required属性
                        boolean required = determineRequiredStatus(ann);
                        if (required) {
                            if (!candidates.isEmpty()) {
                                // 这里也是一样的,有required的构造器,就不预约有其他被
                                // @Autowired注解修饰的构造器了
                                throw new BeanCreationException(...);
                            }
                            // requiredConstructor只能有一个
                            requiredConstructor = candidate;
                        }
                        // 符合条件的构造器加入列表-即有@Autowired的构造器
                        candidates.add(candidate);
                    }
                    else if (candidate.getParameterCount() == 0) {
                        // 如果构造器的参数为空,那就是默认构造器了
                        defaultConstructor = candidate;
                    }
                }
                
                if (!candidates.isEmpty()) {
                    // 如果被@Autowired修饰的构造器不为空
                    if (requiredConstructor == null) {
                        // 如果没有requiredConstructor,就把默认构造器加入列表
                        // 如果有requiredConstructor,实际上candidates中就只有一个构造器了
                        if (defaultConstructor != null) {
                            candidates.add(defaultConstructor);
                        }
                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                            logger.info(...);
                        }
                    }
                    // 然后把candidates列表赋值给返回值
                    candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                }
                else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                    // 如果当前类总共也只有一个构造器,并且这个构造器是需要参数的
                    // 那就直接使用这个构造器了
                    // 这就是为什么我们平常构造器注入不打@Autowired注解也可以的原因
                    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                }
                // 以下主要是处理primaryConstructor的,我们就不读了
                else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                         defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                }
                else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor};
                }
                else {
                    // 都不满足,就是空数组了
                    candidateConstructors = new Constructor<?>[0];
                }
                // 处理完之后放入缓存
                this.candidateConstructorsCache.put(beanClass, candidateConstructors);
            }
        } 
    }
    // 之所以上面解析的时候,没找到构造器也是使用空数组而不是null
    // 就是为了从缓存拿的时候,能区分究竟是没处理过(null),还是处理了但是找不到匹配的(空数组)
    // 避免缓存穿透
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

如果能找到合适的构造器的话,就可以直接通过反射实例化对象了~

3.2. 通过beanPostProcessor埋点来收集注解信息

通过createBeanInstance创建完类的实例之后,注入属性之前,我们有一个beanPostProcessor的埋点方法的调用:

synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
        try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(...);
        }
        mbd.postProcessed = true;
    }
}
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
            bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }
}

由于这个埋点中有一部分对注解进行支撑的逻辑还挺重要的,所以这里单独拿出来讲一下。

3.2.1. CommonAnnotationBeanPostProcessor收集@PostConstruct@PreDestroy@Resource信息

CommonAnnotationBeanPostProcessor也是AnnotationConfigUtils#registerAnnotationConfigProcessors方法注入的,这里我就不带大家再看了。由于CommonAnnotationBeanPostProcessor实现了MergedBeanDefinitionPostProcessor接口,所以在这个埋点中也会被调用到,我们来看一下这个逻辑:

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
    implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable{
    // 构造器
    public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
        // 给两个关键字段设置了
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}
    
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 这里调用了父类的方法,正真的收集`@PostConstruct`、`@PreDestroy`注解的逻辑是在这里做的
        super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
        // 这里就是收集@Resource注解的信息啦
        InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
        // 检查一下
        metadata.checkConfigMembers(beanDefinition);
    }
}
3.2.1.1. 生命周期注解@PostConstruct@PreDestroy信息收集

我们先看一下父类收集生命周期注解的实现:

public class InitDestroyAnnotationBeanPostProcessor
    implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable{
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 寻找生命周期元数据
        LifecycleMetadata metadata = findLifecycleMetadata(beanType);
        // 对收集到的声明周期方法做一下校验处理
        metadata.checkConfigMembers(beanDefinition);
    }

    private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
        if (this.lifecycleMetadataCache == null) {
            // 没有开启缓存就直接拿构建生命周期元数据了
            return buildLifecycleMetadata(clazz);
        }
        // 有开启缓存的话,就先从缓存找,找不到再构建,然后丢回缓存
        LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
        if (metadata == null) {
            synchronized (this.lifecycleMetadataCache) {
                metadata = this.lifecycleMetadataCache.get(clazz);
                if (metadata == null) {
                    // 构建
                    metadata = buildLifecycleMetadata(clazz);
                    this.lifecycleMetadataCache.put(clazz, metadata);
                }
                return metadata;
            }
        }
        return metadata;
    }
    
    private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        // 简单判断类上是不是一定没有initAnnotationType和destroyAnnotationType这两个注解修饰的方法
        // 相当于快速失败
        // 需要注意的是,当前场景下,这两个注解实例化的时候已经初始化为PostConstruct和PreDestroy了
        if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
            return this.emptyLifecycleMetadata;
        }
		// 用来储存类上所有初始化/销毁方法的容器
        List<LifecycleElement> initMethods = new ArrayList<>();
        List<LifecycleElement> destroyMethods = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            // 中间容器来储存当前类的初始化/销毁方法
            final List<LifecycleElement> currInitMethods = new ArrayList<>();
            final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
			// 循环类上的每一个方法
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                    // 如果方法被@PostConstruct注解修饰,包装成一个LifecycleElement
                    LifecycleElement element = new LifecycleElement(method);
                    // 加入收集初始化方法的中间容器
                    currInitMethods.add(element);
                }
                if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                    // 如果方法被@PreDestroy注解修饰,包装成一个LifecycleElement
                    // 加入收集销毁方法的中间容器
                    currDestroyMethods.add(new LifecycleElement(method));
                }
            });
			// 加入所有初始化/销毁方法的容器
            // 需要注意的是,在整个循环过程中,
            // 当前类的初始化方法都是加入初始化方法容器的头部
            // 当前类的销毁方法都是加入销毁方法容器的尾部
            // 所以可以推断,初始化方法调用的时候是从父类->子类调用
            // 而销毁方法从子类->父类调用。
            // 即 bean初始化->调用父类初始化方法->调用子类初始化方法->...->调用子类销毁方法->调用父类销毁方法->销毁bean
            initMethods.addAll(0, currInitMethods);
            destroyMethods.addAll(currDestroyMethods);
            // 获取父类,循环处理所有父类上的初始化/销毁方法
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
		// 把当前类class对象+初始化方法列表+销毁方法列表封装成一个LifecycleMetadata对象
        return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
                new LifecycleMetadata(clazz, initMethods, destroyMethods));
    }
}

看一下这个生命周期元数据LifecycleMetadata的结构:

private class LifecycleMetadata {
    // 目标类
    private final Class<?> targetClass;
    // 目标类上收集到的初始化方法
    private final Collection<LifecycleElement> initMethods;
    // 目标类上收集到的销毁方法
    private final Collection<LifecycleElement> destroyMethods;
    // 检查、校验后的初始化方法
    @Nullable
    private volatile Set<LifecycleElement> checkedInitMethods;
    // 检查、校验后的销毁方法
    @Nullable
    private volatile Set<LifecycleElement> checkedDestroyMethods;
    
    public void checkConfigMembers(RootBeanDefinition beanDefinition) {
        // 这是那个检查、校验方法
        Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
        for (LifecycleElement element : this.initMethods) {
            // 循环处理每个初始化方法
            String methodIdentifier = element.getIdentifier();
            // 判断是否是标记为外部处理的初始化方法,
            // 如果是外部处理的方法的话,其实spring是不会管理这些方法的
            if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
                // 这里把当前方法注册到这个externallyManagedDestroyMethods
                // 我猜想是方法签名相同的方法就不调用两次了
                // 比如可能父类的方法打了@PostConstruct,子类重写之后也在方法上打了@PostConstruct
                // 这两个方法都会被收集到initMethods,但是当然不应该调用多次
                beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
                // 加入了检查后的初始化方法列表,实际调用初始化方法时也是会调用这个列表
                checkedInitMethods.add(element);
            }
        }
        // 销毁方法的处理逻辑和初始化方法一样,我直接跳过了
        this.checkedInitMethods = checkedInitMethods;
        this.checkedDestroyMethods = checkedDestroyMethods;
    }
}

到这里为止,其实我们CommonAnnotationBeanPostProcessor对生命周期注解的收集过程就完成了,其实主要是通过父类的模本方法,把被@PostConstruct@PreDestroy修饰的方法的信息封装到了LifecycleMetadata。看完InitDestroyAnnotationBeanPostProcessor的逻辑之后,同学们会不会有实现一套自己的生命周期注解的冲动呢?毕竟写一个类继承一下然后在自己的类构造器中set一下initAnnotationTypedestroyAnnotationType就可以了!

3.2.1.2. 依赖注入注解@Resource信息收集

刚刚有说道我们的findResourceMetadata方法是用来收集@Resource注解信息的,我们现在来看一下这里的逻辑:

private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
    // 也是一个缓存逻辑
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                // 构建逻辑
                metadata = buildResourceMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    // 这个方法除了收集@Resource注解之外,
    // 其实还会收集@WebServiceRef和@EJB注解(如果你的项目有引入这些)
    // 不过由于@WebServiceRef和@EJB我们现在基本也不用了(反正我没用过)
    // 我这边就把相应的逻辑删除掉了,这样看也清晰点
    // 而且这些收集逻辑也是一致的,最多只是说最后把注解信息封装到不同的子类型而已
    // 快速失败检测
    if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }
	// 收集到注入元素
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        // 这里套路其实跟收集生命周期注解差不多了
        // 也是循环收集父类的
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        // 循环处理每个属性
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            if (...) {...} // 其他注解的处理
            else if (field.isAnnotationPresent(Resource.class)) {
                // 静态属性不允许注入,当然其实@Autowired和@Value也是不允许的,
                // 只是那边不会报错,只是忽略当前方法/属性而已
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException(...);
                }
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    // 不是忽略的资源就加入容器
                    // ejb那些就是封装成EjbRefElement
                    currElements.add(new ResourceElement(field, field, null));
                }
            }
        });
		// 循环处理每个方法,比如@Resource修饰的set方法啦(当然没规定要叫setXxx)
        // 这里会循环当前类声明的方法和接口的默认(default)方法
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            // 这里是处理桥接方法的逻辑,桥接方法是编译器自行生成的方法。
            // 主要跟泛型相关,这里也不多拓展了
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            // 由于这个工具类的循环是会循环到接口的默认方法的
            // 这里这个判断是处理以下场景的:
            // 接口有一个default方法,而当前类重写了这个方法
            // 那如果子类重写的method循环的时候,这个if块能进去
            // 接下来接口的相同签名的默认method进来时,
            // ClassUtils.getMostSpecificMethod(method, clazz)会返回子类中重写的那个方法
            // 这是就和当前方法(接口方法)不一致,就不会再进if块收集一遍了
            if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                if (...) {...} // 其他注解的处理
                else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException(...);
                    }
                    Class<?>[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length != 1) {
                        // 原来@Resource方法注入只支持一个参数的方法(set方法)
                        // 这个限制估计是规范定的
                        // @Autowired没有这个限制
                        throw new IllegalStateException(...);
                    }
                    if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                        // 封装了一个属性描述符,这个主要用来加载方法参数的,暂时不展开
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        // 也封装成一个ResourceElement加入容器
                        currElements.add(new ResourceElement(method, bridgedMethod, pd));
                    }
                }
            }
        });
		// 每次都放到列表的最前面,说明是优先会注入父类的
        elements.addAll(0, currElements);
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);
	// 把当前类的class和收集到的注入元素封装成一个注入元数据
    return InjectionMetadata.forElements(elements, clazz);
}

可以看到,其实跟生命周期那一块差不多,也是收集注解信息然后封装,只是这个注入元素的收集要同时收集属性和(set)方法而已,我们还是照常瞄一下这个数据结构:

public class InjectionMetadata {
    // 目标类--属性需要注入到哪个类
    private final Class<?> targetClass;
	// 注入元素
    private final Collection<InjectedElement> injectedElements;
	// 检查后的注入元素
    @Nullable
    private volatile Set<InjectedElement> checkedElements;
}

public abstract static class InjectedElement {
		// Member是Method和Field的父类
		protected final Member member;
		// 通过这个属性区分是field还是method
		protected final boolean isField;
		// 属性描述符,如果是method会通过这个描述符获取入参
		@Nullable
		protected final PropertyDescriptor pd;
		@Nullable
		protected volatile Boolean skip;
}

获取到InjectionMetadata之后的metadata.checkConfigMembers逻辑,和生命周期那一块是一模一样的,这边就不跟了。

那么到这里为止我们CommonAnnotationBeanPostProcessor类在bean实例创建之后的埋点的逻辑就分析完了。

3.2.2. AutowiredAnnotationBeanPostProcessor收集@Autowired@Value信息

AutowiredAnnotationBeanPostProcessor这个类的注册时机已经讲过很多遍了,也是AnnotationConfigUtils#registerAnnotationConfigProcessors方法注入的,这边我们直接看一下它的postProcessMergedBeanDefinition方法是如何收集注解信息的:

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
    implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
    // 自动注入注解类型
    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
    
    public AutowiredAnnotationBeanPostProcessor() {
        // autowiredAnnotationTypes中放入@Autowired、@Value
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
        try {
            this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                                              ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }
    
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 这里其实就很熟悉了,和@Resource的处理过程看起来就是一模一样的
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }
	
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        // 缓存逻辑我这边就不看了,都是一模一样的
        // 这个,其实连收集逻辑都基本是一致的,我们就简单过一下吧
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        }

        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			// 处理属性
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    // 静态属性不允许注入
                    if (Modifier.isStatic(field.getModifiers())) {
                        return;
                    }
                    // @Autowrired有一个required属性需要收集一下
                    boolean required = determineRequiredStatus(ann);
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });
			// 处理方法
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    if (Modifier.isStatic(method.getModifiers())) {
						// 静态方法不处理,忽略,相当于不生效,@Resource那边是会报错的。
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    // 封装一个属性描述符描述符
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });
			// 父类优先
            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
		// 封装到InjectionMetadata
        return InjectionMetadata.forElements(elements, clazz);
    }
}

啊,索然无味,这个逻辑简直跟@Resource的处理一模一样的,同学们有没有一丢丢疑惑--这样如此雷同的方法,spring为什么要写两遍呢?这是不是违反了DRY原则呢?同学们可以思考一下这个问题。

我倒是认为没有违反DRY原则,但是对于javax.inject.Inject注解的划分还是不太合适,应该划分到common的;而common中对各种类型的注解的处理(@EJB@Resource@WebServiceRef)使用if-else也不太优雅,完全可以使用一个小小的策略模式的。

不过这东西每个人看法也不一样的,同学们有兴趣也可以在评论区探讨一下~

3.2.3. 总结CommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessor

这个埋点基本上就这两个beanPostProcessor做了事情了,而且也与我们平常的开发息息相关,这边简单总结一下。

3.2.3.1 职能划分

这两个beanPostProcessor的职能上是有划分的:

  1. CommonAnnotationBeanPostProcessor主要处理jdk相关的规范的注解,@Resource@PostConstruct等注解都是jdk的规范中定义的。

    • 收集生命周期相关的@PostConstruct@PreDestroy注解信息封装成LifecycleMetadata
    • 收集资源注入注解(我们主要关注@Resource)信息封装成InjectionMetadata
  2. AutowiredAnnotationBeanPostProcessor主要处理spring定义的@Autowired相关的功能

    • 这里不得不说一下我觉得这个类也用来处理javax.inject.Inject不合理

    • 收集自动注入相关的注解@Autowired@Value信息封装成InjectionMetadata

3.2.3.2 使用@Resouce还是@Autowired

那么日常我们开发过程中,究竟推荐使用@Resouce还是@Autowired呢?这个问题我认为仁者见仁智者见智,我这边只稍微列一下使用这两个注解时需要注意的问题:

  1. @Resouce@Autowired都不能用来注入静态属性(通过在静态属性上使用注解和静态方法上使用注解)
  2. 使用@Resouce注入静态属性时,会直接抛出IllegalStateException导致当前实例初始化流程失败
  3. 而使用@Autowired注入静态属性时,只会忽略当前属性,不注入了,不会导致实例初始化流程失败
  4. 使用@Resouce修饰方法时,方法只能有一个入参,而@Autowired没有限制
  5. @Resouce属于jdk的规范,可以认为对项目零入侵;@Autowired属于spring的规范,使用了@Autowired的话就不能替换成别的IOC框架了(这个我确实也没替换过...)

(由于掘金对文章字数的限制,这篇博文被迫分为上下两篇,点击前往下一篇

创作不易,转载请篇首注明 作者:掘金@小希子 + 来源链接~

如果想了解更多Spring源码知识,点击前往其余逐行解析Spring系列

٩(* ఠO ఠ)=3⁼³₌₃⁼³₌₃⁼³₌₃嘟啦啦啦啦。。。

这里是新人博主小希子,大佬们都看到这了,左上角点个赞再走吧~~