深入理解 Spring Bean 的生命周期

摘要

        Spring 是当下热门的框架,其根本使命是为了简化企业级的 Java 开发,因此其提供了依赖注入以及面向切面编程这两大核心特性。而在 Spring 框架的使用中 Spring Bean 贯穿始终,那么 Spring Bean 是如何创建的,它的生命周期又是如何?本篇文章正是解答这个问题。

关键词:Spring Bean、Spring、Java

1、引言

        什么是 Spring Bean 的生命周期?在回答这个问题之前我们应该明白什么是 bean。在传统的程序设计中,应用程序的代码通常控制着对象的创建与管理,但是在 Spring 中发生了转变,对象的创建与管理交由 Spring 容器,对象的控制权被转移到容器中,容器负责管理对象,并在需要的时候将对象注入到应用程序中,而这一现象又被称为依赖注入(DI),也就是 Spring 的核心特性之一。由 Spring 容器所管理的对象就是 bean。

图1-1 spring 容器对 bean 对象的管理

        对于普通的对象在不使用后则会有 JVM 的垃圾回收器进行回收,由用户创建对象并使用,不再使用后就有垃圾回收器进行回收,这就是普通对象的生命周期。而对于 bean,是由 Spring IOC 容器创建和管理的,因此它的创建、使用以及销毁都是由 IOC 容器进行控制,而这就是 Spring Bean 的生命周期。

2、相关工作

2.1 Spring Bean 创建的详细流程

        一个 Spring Bean 从创建到销毁需要经历实例化、初始化、销毁回调函数注册、使用、销毁这五大阶段。而在初始化阶段中,又可以细分为属性注入、相关 Aware 的注入、自定义初始化方法的调用、初始化后置操作。在销毁阶段中可细分为 DisposableBean 处理以及自定义销毁方法的调用。

图2-1 Spring Bean 生命周期

        由图 2-1 可知,在 Spring Bean 的实例化之前还有一步操作,那就是获取这个 bean 的信息,而 bean 的实例化正是根据这个 bean 的信息来的。本章节接下来就会围绕图 2-1 来详细说明 Spring Bean 的生命周期,这里所说的生命周期主要是指的 singleton bean,对于 prototype 的 bean,Spring 在交给使用者后便不会再管理接下来的生命周期。因此,此处需要先说明 Spring Bean 有哪几种作用域。

singletong(单例)默认作用域,对于每个 Spring IOC 容器,只创建一个 Bean 实例,适用于全局共享的状态,因此如果处于此作用域下的 bean 是有状态 bean,那么它是线程不安全的。
prototype(原型)每次请求都会创建一个新的 Bean 实例,适用于所有状态都是非共享的情况。
request(请求)仅在 Web 应用程序中有效,每个 HTTP 请求都会创建一个新的 Bean 实例,适用于请求级别的数据存储和处理。
session(会话)仅在 Web 应用程序中有效,每次连接建立的会话都会创建一个新的 Bean 实例,适用于会话级别的数据存储和处理。
application(应用)仅在 Web 应用程序中有效,在 ServletContext 的生命周期内,只创建一个 Bean 实例,适用于全应用程序级别的共享数据。
websocket仅在 Web 应用程序中有效,在 websocket 的生命周期内,只创建一个 Bean 实例,适用于 websocket 级别的共享数据。

表2-1 Spring Bean 的作用域

2.2 加载 Bean 信息以及 Bean 的实例化

        在 Spring 应用启动时,会调用 AbstractApplicationContext 抽象类中的 refresh 方法。

图2-2 refresh 方法位置

        在该方法中调用了 finishBeanFactoryInitialization 方法,而在 finishBeanFactoryInitialization  方法中又调用了 preInstantiateSingletons 方法,通过追查可以发现这个方法是由 ConfigurableListableBeanFactory 接口所提供的,而实现该方法的是 DefaultListableBeanFactory

图2-3 ConfigurableListableBeanFactory 接口中的方法

图2-4 DefaultListableBeanFactory 中的 preInstantiateSingletons 方法一部分截图

        图 2-4 中红色框中的代码便是构建 Spring Bean 的一段核心代码,代码首先获取了要实例化的 bean 信息,并且判断该 bean 定义是否不是抽象(!mbd.isAbstract())且是单例的(mbd.isSingleton())。如果是就尝试通过 preInstantiateSingleton 方法实例化这个 bean,在 preInstantiateSingleton 方法中又会去调用 getBean 方法,并在 getBean 方法中接着调用位于AbstractBeanFactory 中的 doGetBean 方法。

图2-5 doGetBean 方法一部分截图

        由图 2-5 可知会根据 bean 信息来判断该 bean 的作用域是不是单例,如果是则执行 getSingleton 方法,该方法需要传入 beanName 以及一个工厂,由工厂来提供 bean 对象。而进入 createBean 方法后,我们就进入了一个十分核心的类,AbstractAutowireCapableBeanFactory。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Creating instance of bean '" + beanName + "'");
        }

        // RootBeanDefinition是BeanDefinition的一个具体实现,提供了最全面的Bean定义信息。
        RootBeanDefinition mbdToUse = mbd;

        // 拿到该 bean 的类对象
        Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);

        // 类对象不为空,且mbd中并没有记录类对象,mbd又提供了类名时
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            // 包装一边 bean 信息,向其中添加该 bean 的类对象
            mbdToUse.setBeanClass(resolvedClass);

            try {
                // 检查重写方法,以确保它们符合预期
                mbdToUse.prepareMethodOverrides();
            } catch (BeanDefinitionValidationException var9) {
                throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
            }
        }

        Object beanInstance;
        try {
            // 这段代码在Bean实例化之前尝试解析并返回一个Bean实例,或者确定是否应该跳过常规的实例化过程
            beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
            if (beanInstance != null) {
                return beanInstance;
            }
        } catch (Throwable var10) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
        }

        try {
            // 此处做常规的实例化
            beanInstance = this.doCreateBean(beanName, mbdToUse, args);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Finished creating instance of bean '" + beanName + "'");
            }

            return beanInstance;
        } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
            throw var7;
        } catch (Throwable var8) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
        }
    }

        通过分析上述源码可以知道创建一个 bean,需要获取该 bean 的定义信息,并且会对 bean 的定义信息做检验,检验通过后便可以去获得一个 bean 对象,获取途径又常规获取和非常规获取,而非常规获取是如何获取,它做了什么,常规获取又是如何获取?接下来便解答这两个问题。

    @Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        // 该对象是用于存储可能会从BeanPostProcessor返回的bean实例
        Object bean = null;

        // 检查beforeInstantiationResolved标志,如果没有解析过,则执行里面的逻辑
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {

            // 检查mbd是否不是spring自动生成,并且该bean实现过InstantiationAwareBeanPostProcessors
            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {

                // 获取bean的类对象
                Class<?> targetType = this.determineTargetType(beanName, mbd);
                if (targetType != null) {
                    // 遍历所有InstantiationAwareBeanPostProcessor的实现,并返回一个bean
                    bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        // 如果bean不为空,并且这个实例需要进一步的初始化后处理
                        bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }

            // 如果bean不空则将标志设置为经过解析了
            mbd.beforeInstantiationResolved = bean != null;
        }

        return bean;
    }

        通过上述源码可以知道,首先准备一个用于接收可能通过 BeanPostProcessor 返回的 bean 实例,并检查 bean 信息,如果 beforeInstantiationResolved 标志为 false 则进入后续逻辑,遍历所有 InstationAwareBeanPostProcessor 的实现,并返回一个 bean,通常应该为 null,如果返回了非 null 的实例,则 Spring 将不会继续执行后续的实例化逻辑,而是直接使用这个返回的实例。applyBeanPostProcessorsAfterInstantiation 方法通常用于 Bean 实例化并初始化之后。然而,如果 applyBeanPostProcessorsBeforeInstantiation 确实返回了一个 Bean 实例,并且这个实例需要进一步的初始化后处理,尽管这在大多数情况下不是预期的,这段代码将允许这种情况发生。但请注意,这通常不是标准的 Spring 行为。最后,根据是否通过 BeanPostProcessor 返回了 Bean 实例来更新 beforeInstantiationResolved 标志。总体来说 resolveBeforeInstantiation 方法是 Spring 框架中 bean 实例化的一部分,它允许在 bean 实例化之前通过 BeanPostProcessor 进行干预,并可能返回一个直接的 bean 实例,从而跳过常规的 bean 实例化过程。

        bean 的常规实例化过程中会包含 bean 对象完整的初始化以及销毁回调函数注册,而本章节主要是讲解 bean 信息以及 bean 的实例化,因此在这里就不给出 doCreateBean 的完整代码,而是取出其中有关 bean 实例化的代码进行分析。在 doCreateBean 中会调用 createBeanInstance 方法,来实例化 bean。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 获取该bean的类对象
        Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);

        // 如果类对象不为空,并且该类对象不是public同时不允许非公开访问的,则抛出异常
        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());
        } else {
            if (args == null) {
                // 如果构造函数参数为空,并且RootBeanDefinition中有一个实例供应商(instanceSupplier),则尝试从这个供应商中获取Bean的实例。这是Spring 5.0引入的一种灵活的方式来创建Bean实例,允许通过Lambda表达式或其他函数式接口来定义Bean的创建逻辑。
                Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
                if (instanceSupplier != null) {
                    return this.obtainFromSupplier(instanceSupplier, beanName, mbd);
                }
            }
            // 如果Bean定义中指定了工厂方法(factoryMethodName),则使用工厂方法来实例化Bean
            if (mbd.getFactoryMethodName() != null) {
                return this.instantiateUsingFactoryMethod(beanName, mbd, args);
            } else {

                // 如果没有使用实例供应商或工厂方法,接下来会检查是否已经解析了Bean的构造函数或工厂方法
                boolean resolved = false;
                boolean autowireNecessary = false;
                if (args == null) {
                    synchronized(mbd.constructorArgumentLock) {
                        if (mbd.resolvedConstructorOrFactoryMethod != null) {
                            resolved = true;
                            autowireNecessary = mbd.constructorArgumentsResolved;
                        }
                    }
                }

                // 如果已经解析,并且需要自动装配,则使用自动装配逻辑来实例化Bean。
                if (resolved) {
                    return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
                } else {
                    
                    // 否则获取其构造函数
                    Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
                    if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
                        // 如果Bean定义中指定了首选构造函数,并且没有其他自动装配的要求或参数,则直接使用这些构造函数进行实例化。
                        ctors = mbd.getPreferredConstructors();
                        return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
                    } else {
                        // 否则根据提供的参数(args)和自动装配的模式,使用最合适的构造函数来实例化Bean。
                        return this.autowireConstructor(beanName, mbd, ctors, args);
                    }
                }
            }
        }
    }

        这段代码展示了 Spring 框架在创建 Bean 实例时的复杂性和灵活性,它支持多种实例化策略,包括使用实例供应商、工厂方法、构造函数自动装配等。最终,这个方法返回一个 BeanWrapper 对象,它封装了新创建的 Bean 实例,允许对其进行进一步的配置和初始化。至此 bean 完成了实例化。

2.3 Bean 的初始化

        基于上一章节取得的 bean 的实例化对象,本章节将基于此来完成 bean 的初始化,在 2.1 章节中简要说明了 bean 的初始化过程,并且图 2-1 中也表明了 bean 初始化需要经过哪些步骤。首先聚焦于 AbstractAutowireCapableBeanFactory 类中的 doCreateBean 方法。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        // 给出一个bean的装饰对象
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // 如果bean是单例的,则从缓存中获取该bean的实例
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            // 如果缓存中没有,则创建一个新的bean实例
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        // 确定bean的类型
        if (beanType != NullBean.class) {
            //如果不是NullBean.class,则更新bean定义中的resolvedTargetType为实际的Bean类型
            mbd.resolvedTargetType = beanType;
        }

        synchronized(mbd.postProcessingLock) {
            // 同步检查bean定义是否已经被后置处理
            if (!mbd.postProcessed) {
                try {
                    // 如果没有,则应用合并后的Bean定义后处理器
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.markAsPostProcessed();
            }
        }

        // 如果bean是单例的,允许循环依赖,并且当前的bean正在创建中
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }

            // 则将该bean的工厂方法添加到三级缓存中,以便在后续解决循环依赖时能够获取到Bean的早期引用
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
            // 进行属性注入
            this.populateBean(beanName, mbd, instanceWrapper);
            // 执行bean的初始化回调
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException bce) {
                if (beanName.equals(bce.getBeanName())) {
                    throw bce;
                }
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, var18.getMessage(), var18);
        }

        // 如果之前暴露了早期单例的bean
        if (earlySingletonExposure) {
            // 尝试从容器中获取指定beanName的早期单例引用,但不创建新的bean实例
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                // 如果exposedObject与当前正在创建的bean实例(bean)相同,则将exposedObject更新为早期单例引用。这通常意味着bean的创建过程已经完成了足够多的工作,可以安全地暴露其早期版本。
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    // 如果不允许原始注入(!this.allowRawInjectionDespiteWrapping)且当前bean有依赖bean(this.hasDependentBean(beanName)),则进一步检查这些依赖bean。
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = CollectionUtils.newLinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }

                    // 如果actualDependentBeans不为空,即存在实际依赖当前bean的bean,并且这些bean在引用当前bean时可能使用的是其原始版本
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            // 如果Bean实现了DisposableBean接口或者定义了销毁方法(destroy-method),则注册销毁回调
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

在上述源码中,已在核心逻辑处都添加了注释,在拥有 bean 的实例化对象以后第一步操作就是对 bean 进行属性注入,也就是调用 populateBean 方法。

2.3.1 属性注入
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            // 如果BeanWrapper为空但是却存在有属性值,则抛出异常
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
        } else if (bw.getWrappedClass().isRecord()) {
            // 如果BeanWrapper包装的类是一个Record类型,并且mbd包含属性值,则同样抛出异常。Record类型是不可变的,因此不能应用属性值。
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
            }
        } else {
            // 如果bean不是合成的,并且存在InstantiationAwareBeanPostProcessor的实现,则遍历这些处理器并调用它们的postProcessAfterInstantiation方法。
            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
                Iterator var4 = this.getBeanPostProcessorCache().instantiationAware.iterator();

                while(var4.hasNext()) {
                    InstantiationAwareBeanPostProcessor bp = (InstantiationAwareBeanPostProcessor)var4.next();
                    // 如果postProcessAfterInstantiation方法返回false,则不再继续填充属性值,直接返回
                    if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        return;
                    }
                }
            }

            // 根据mbd中定义的自动装配模式(resolvedAutowireMode),可能会进行按名称(byName)或按类型(byType)的自动装配
            PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;
            int resolvedAutowireMode = mbd.getResolvedAutowireMode();
            if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {
                MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
                if (resolvedAutowireMode == 1) {
                    this.autowireByName(beanName, mbd, bw, newPvs);
                }

                if (resolvedAutowireMode == 2) {
                    this.autowireByType(beanName, mbd, bw, newPvs);
                }

                pvs = newPvs;
            }

            // 如果InstantiationAwareBeanPostProcessors的实现
            if (this.hasInstantiationAwareBeanPostProcessors()) {
                if (pvs == null) {
                    pvs = mbd.getPropertyValues();
                }

                PropertyValues pvsToUse;
                for(Iterator var11 = this.getBeanPostProcessorCache().instantiationAware.iterator(); var11.hasNext(); pvs = pvsToUse) {
                    InstantiationAwareBeanPostProcessor bp = (InstantiationAwareBeanPostProcessor)var11.next();
                    // 并且bean有属性值(或者之前通过自动装配生成了新的属性值),则遍历这些处理器并调用它们的postProcessProperties方法。这允许处理器修改属性值。
                    pvsToUse = bp.postProcessProperties((PropertyValues)pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        return;
                    }
                }
            }

            boolean needsDepCheck = mbd.getDependencyCheck() != 0;
            if (needsDepCheck) {
                // 如果需要进行依赖检查,则执行依赖检查。这涉及到过滤出需要检查的属性描述符,并调用checkDependencies方法来确保这些依赖已经被正确解析。
                PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);
            }

            // 如果bean有属性值
            if (pvs != null) {
                // 则调用applyPropertyValues方法将这些属性值应用到bean实例上
                this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
            }

        }
    }

        这段代码是 Spring IOC 容器中 bean 填充过程中的核心。首先会检查是否有实例化的 bean,并且 bean 信息中是否存在有属性值,如果存在实例化的 bean,并且 bean 信息中存在有属性值的话,则进行属性注入。在进行属性注入前有一个很关键的判断就是检查所有实现了 InstantiationAwareBeanPostProcessor 中的 postProcessorAfterInstantation 方法,如果有返回 false 的情况就不再进行接下来的属性注入。根据 mbd 中定义的自动装配模式,可能会进行按名称或按类型的自动装配。接下来再次应用  InstantiationAwareBeanPostProcessor,调用它的所有实现,并且 bean 有属性值或者之前通过自动装配生成了新的属性值,则遍历这些处理器并调用它们的 postProcessProperties 方法来修改属性值。

        populateBean 方法处理了 bean 实例的实例化后阶段,包括属性值的应用、自动装配、依赖检查等任务,同时提供了通过 InstantationAwareBeanPostProcessor 扩展点的机制来允许用户自定义 bean 的填充过程。

2.3.2 initializeBean 方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        // 检查Aware
        this.invokeAwareMethods(beanName, bean);
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 调用BeanPostProcessor的前置处理方法
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
            // 调用InitializingBean的afterPropertiesSet方法或者自定义init-method方法
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, var6.getMessage(), var6);
        }

        if (mbd == null || !mbd.isSynthetic()) {
            // 调用BeanPostProcessor的后置处理方法
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

        检查 Aware 就是检查是否实现了 BeanNameAware、BeanClassLoaderAware 以及 BeanFactoryAware 这些 Aware 接口,Spring 容器会调用它们的方法进行处理。这些 Aware 接口提供了一种机制,使得 Bean 可以与 Spring 框架的内部组件交互,从而更灵活地利用 Spring 框架提供的功能。

        在检查 Aware 后便开始调用 BeanPostProcessor 的前置处理方法,BeanPostProcessor 是 Spring IOC 容器提供的一个扩展接口,其主要作用是帮助在 Bean 的初始化前后额外添加一些自定义的逻辑,通过查看源码可以发现调用 BeanPostProcessor 的前置处理方法是在 applyBeanPostProcessorsBeforeInitialization 方法中。

图2-6 applyBeanPostProcessorsBeforeInitialization 方法

图2-7 实现了 BeanPostProcessor 的类

        从图 2-6 中可以看出时调用了 postProcessorsBeforeInitialization 方法,再从图 2-7 中可以看出有众多实现类,选择其中 ApplicationContextAwareProcessor 来查看该方法的具体实现是如何的。

图2-8 ApplicationContextAwareProcessor 中 invokeAwareInterfaces 方法

        在 ApplicationContextAwareProcessor 的 postProcessorsBeforeInitialization 方法中最后是调用的 invokeAwareInterfaces 方法,从图 2-8 可以看出,其核心依旧是检查并设置 Aware。通过进入 initializeBean 方法到目前一直在做的工作就是检查并设置 Aware,那么什么是 Aware?

        Spring 文档中是这样解释的 Aware 接口的,Spring 提供了广泛的 Aware 回调接口,让 bean 向容器表明它们需要某种基础设施依赖。

        也就是说通过 Aware 接口提供了一种让 Bean 能够获取容器或其他相关资源的方式,从而简化了在 Bean 中使用这些资源的过程。在 Spring 中有如下 Aware。

名称用途所属容器
BeanNameAware获取 bean 名称BeanFactory
BeanClassLoaderAware获取 bean 的类加载器BeanFactory
BeanFactoryAware获取 bean 工厂(建议用下面的BeanFactory
EnvironmentAware获取环境相关信息,如属性、配置信息等ApplicationContext
EmbeddedValueResolverAware获取值解析器ApplicationContext
ResourceLoaderAware获取资源加载器ApplicationContext
ApplicationEventPublisherAware获取事件广播器,发布事件使用ApplicationContext
MessageSourceAware获取消息资源ApplicationContext
ApplicationStartupAware提供对Spring应用程序启动过程的细粒度跟踪能力ApplicationContext
ApplicationContextAware获取ApplicationContextApplicationContext

​​​​​​​表2-2 Spring 中的 Aware

        在执行完 BeanPostProcessor 的前置处理方法之后,便执行 invokeInitMethods 方法,通过查看该方法的源码,可以发现在执行自定义的初始化方法时,是优先执行 afterPropertiesSet 方法,再执行 init-method 方法。

图2-9 AbstractAutowireCapableBeanFactory 的 invokeInitMethods 方法

        通过图 2-9 可以知道 afterPropertiesSet 和 init-method 方法执行的先后顺序,但是还有一个 @PostConstruct 注解表明的初始化方法,这个方法由是什么样的顺序执行呢?这里就需要查看 BeanPostProcessor 的另一个实现类 InitDestroyAnnotationBeanPostProcessor。查看其中 postProcessBeforeInitialization 方法,可以发现其中调用了 findLifecycleMetadata 方法。

图2-10 InitDestroyAnnotationBeanPostProcessor 的 findLifecycleMetadata 方法

        从图 2-10 可以看出 findLifecycleMetadata 方法中的核心逻辑就是 buildLifecycleMetadata,而 buildLifecycleMetadata 方法就是在寻找 bean 中有没有哪些方法上有 initAnnotationType 注解,如果有,那么就把它添加到 initMethods 中,返回给前面的方法执行。而存储 initAnnotationType 注解的是一个集合。

private final Set<Class<? extends Annotation>> initAnnotationTypes = new LinkedHashSet(2);

        而其中的值是从 CommonAnnotationBeanPostProcessor 的构造函数执行时添加的,见图 2-11。

图2-11 CommonAnnotationBeanPostProcessor 的构造函数

        经过上述分析便知道在 CommonAnnotationBeanPostProcessor 初始化的时候,会把 PostConstruct 设置到 initAnnotationTypes 中,然后在 InitDestroyAnnotationBeanPostProcessor 的 postProcessBeforeInitialization 方法执行过程中,会检查这个 Bean 中有哪些 initAnnotationType,把加了 initAnnotationType 注解的方法当作初始化方法进行调用。所以 @PostConstruct 注解表明的初始化方法,在执行 BeanPostProcessor 的前置处理方法的时候就已经调用。

        至此 bean 的初始化还剩下的就是执行 BeanPostProcessor 的后置处理方法。调用后置处理方法是在 initializeBean 方法中的 applyBeanPostProcessorsAfterInitialization 方法中执行的。

图2-12 AbstractAutowireCapableBeanFactory 的 applyBeanPostProcessorsAfterInitialization 方法

        从源码中可以知道,它就是遍历执行 BeanPostProcessor 的后置处理方法,这里有一个很关键的后置处理方法,就是 AnnotationAwareAspectJAutoProxyCreator 类中的后置处理方法,它也是 BeanPostProcessor 的实现,它之所以重要是因为在它的后置处理方法中完成 AOP 代理的创建。

        至此便完成了 bean 的初始化工作,剩下的便是注册销毁回调函数。

2.4 注册销毁回调函数

        在 doCreateBean 方法中还有一个非常重要的代码,那就是注册销毁回调函数,而注册销毁回调函数的方式可以是实现 DisposableBean 接口,也可以是在 bean 中指定了自定义的销毁方法,Spring 容器会为这些 bean 注册一个销毁回调,确保在容器关闭时能够正确地清理资源。

图2-13 AbstractAutowireCapableBeanFactory 的 doCreateBean 方法的部分截图

        进入该方法,可以看到如下源码。

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        if (!mbd.isPrototype() && this.requiresDestruction(bean, mbd)) {
            if (mbd.isSingleton()) {
                // 将该bean注册为需要销毁的bean
                this.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessorCache().destructionAware));
            } else {
                Scope scope = (Scope)this.scopes.get(mbd.getScope());
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
                }

                scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, this.getBeanPostProcessorCache().destructionAware));
            }
        }

    }

        该方法首先判断 bean 的作用域是否不是原型作用域,因为原型作用域的 bean 是由容器每次请求时创建的,并且容器不负责其销毁,通常由使用方负责(GC 回收),所以不需要注册销毁回调。然后再检查 bean 是否要求销毁操作,如果要求则进入后续逻辑,判断 bean 是否是单例作用域,如果是则将该 bean 注册为要销毁的 bean。这里 Spring 使用 DisposableBeanAdapter 作为适配器,将 bean 的销毁逻辑封装起来,以便在容器关闭时调用。而如果 bean 不是单例作用域,那么需要从所有已注册的作用域中获取该 bean 的作用域,若找到了对应的作用域,则调用该作用域的 registerDestructionCallback 方法,注册一个销毁回调,这个销毁回调同样使用 DisposableBeanAdapter 作为适配器,以便在结束时调用 bean 的销毁逻辑。若发现没有注册对应的 bean,则抛出异常,因为这意味着 Spring 容器无法管理该作用域下的 bean 的生命周期。

private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap();

......

public void registerDisposableBean(String beanName, DisposableBean bean) {
    synchronized(this.disposableBeans) {
        this.disposableBeans.put(beanName, bean);
    }
}

        可以看到所谓的将 bean 注册为需要销毁的 bean,就是将该 bean 存入一个哈希表中。

2.5 Bean 的销毁

        到本章节 bean 就已经完成了其实例化、初始化、注册销毁回调的步骤,至于 bean 的使用便跳过,因为只要使用 Spring 框架来开发应用,那么 bean 的使用是再常见不过的,所以直接来到 bean 的生命周期的最后一站,bean 的销毁。

        在 2.4 章节中讲述销毁回调函数注册的时候就频繁提起一个类,DisposableBeanAdapter 类。这个类之所以频繁提起是因为在 Spring 容器关闭时会调用其 destroy 方法。

public void destroy() {
        if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
            Iterator var1 = this.beanPostProcessors.iterator();

            while(var1.hasNext()) {
                DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
                // 执行销毁前置处理
                processor.postProcessBeforeDestruction(this.bean, this.beanName);
            }
        }

        String msg;
        if (this.invokeDisposableBean) {
            // 如果该bean实现了DisposableBean则进入
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
            }

            try {
                // 执行该bean的destroy方法
                ((DisposableBean)this.bean).destroy();
            } catch (Throwable var7) {
                if (logger.isWarnEnabled()) {
                    msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
                    if (logger.isDebugEnabled()) {
                        logger.warn(msg, var7);
                    } else {
                        logger.warn(msg + ": " + var7);
                    }
                }
            }
        }

        if (this.invokeAutoCloseable) {
            // 如果该bean实现了AutoCloseable接口则进入
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking close() on bean with name '" + this.beanName + "'");
            }

            try {
                // 调用该bean的close方法
                ((AutoCloseable)this.bean).close();
            } catch (Throwable var6) {
                if (logger.isWarnEnabled()) {
                    msg = "Invocation of close method failed on bean with name '" + this.beanName + "'";
                    if (logger.isDebugEnabled()) {
                        logger.warn(msg, var6);
                    } else {
                        logger.warn(msg + ": " + var6);
                    }
                }
            }
        } else {
            int var3;
            int var11;
            if (this.destroyMethods != null) {
                // 如果该bean指定了自定义销毁方法,并通过反射获取到则进入
                Method[] var8 = this.destroyMethods;
                var11 = var8.length;

                for(var3 = 0; var3 < var11; ++var3) {
                    Method destroyMethod = var8[var3];
                    // 执行自定义销毁方法
                    this.invokeCustomDestroyMethod(destroyMethod);
                }
            } else if (this.destroyMethodNames != null) {
                //如果destroyMethods为空但destroyMethodNames不为空,说明是通过方法名来指定销毁方法的,则进入
                String[] var9 = this.destroyMethodNames;
                var11 = var9.length;

                for(var3 = 0; var3 < var11; ++var3) {
                    String destroyMethodName = var9[var3];
                    // 根据方法名来获取销毁方法
                    Method destroyMethod = this.determineDestroyMethod(destroyMethodName);
                    if (destroyMethod != null) {
                        // 执行销毁方法
                        this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass()));
                    }
                }
            }
        }

    }

        根据源码可以看出首先执行的是销毁的前置方法,查看该方法可以发现这是一个接口提供的,该接口继承了 BeanPostProcessor。

图2-14 DestructionAwareBeanPostProcessor 接口

        在该接口的实现类中会发现 InitDestroyAnnotationBeanPostProcessor,这个类在本文的 2.3.2 小节中提到过,在该小节中讲述了 postProcessBeforeInitialization 方法,并引出了 CommonAnnotationBeanPostProcessor 类,从图 2-11 可以发现除了将 PostConstruct 设置到 initAnnotationTypes 中,同时也将 PreDestroy 设置到 destroyAnnotationTypes 中。那么接下来看看在 InitDestroyAnnotationBeanPostProcessor 类中其实现的 postProcessBeforeDestruction 方法。

图2-15 InitDestroyAnnotationBeanPostProcessor 中的 postProcessBeforeDestruction 方法

图2-16 buildLifecycleMetadata 方法中的部分截图

        从图 2-15 可以看到一个熟悉的身影 findLifecycleMetadata 方法,该方法除了寻找看哪些 bean 中的方法上有 initAnnotationType 注解,并将有该注解的添加到 initMethods 中外,还会寻找看哪些 bean 中的方法上有 destroyAnnotationType 注解,并将有该注解的添加到 destroyMethods 中,并返回给前面方法继续执行,以此来执行其销毁逻辑。

        接下来便是查看该 bean 是否实现了 DisposableBean 接口,如果实现了则调用其 destroy 方法,以及检查是否实现了 AutoCloseable 接口,如果实现了则调用其 close 方法。最后检查该 bean 是否指定了自定义的销毁方法,如果有则执行。

        至此 bean 的销毁就结束了,也意味着一个 bean 走完了它的一生。

3、实验

        根据第 2 章相关工作中的讲述,已经明白了 bean 的生命周期。而本章节便是给出代码来验证一个 bean 的生命周期是不是如上所说。本实验所用代码将上传至 gitee 仓库(blogs: 本仓库是 爱吃小鱼的橙子 的个人博客中使用到的实验代码的存放仓库 (gitee.com)),文中就不放出只放出结论,如有需要可以自取。

图3-1 实验结论

        从图 3-1 可以看出实验结果符合预期,但是可以发现并没有打印 AutoClosable 接口的 close 方法,这是因为 close 是用于关闭那些启用了资源的 bean,这些 bean 通常代表了一些需要显式关闭的资源,比如数据库连接、文件句柄等。

4、总结与展望

        本章节对本文做一个整体总结,在 Spring 框架中,Bean 的创建过程是一个复杂但高度模块化和灵活的过程,它主要涉及到 Spring 容器(ApplicationContext 或 BeanFactory)的启动和 Bean 的生命周期管理。而一个 bean 从创建到销毁要经历如下的过程

  • 配置文件加载:Spring 容器启动时,首先会加载配置文件(如 XML 配置文件、注解配置等),这些配置文件中包含了 Bean 的定义信息,包括 Bean 的类型、属性、依赖关系等。
  • Bean 定义注册:Spring 读取配置文件中的 Bean 定义信息,并将这些信息转换为 BeanDefinition 对象,这些对象存储在 Spring 容器的内部结构中,如 BeanDefinitionRegistry 中。
  • Bean 的实例化:当需要某个 Bean 时(例如通过 getBean 方法显式请求),Spring 容器会根据 BeanDefinition 中的信息来创建 Bean 的实例,如果 Bean 是单例的(默认情况),Spring 会检查该 Bean 是否已经存在,如果存在则直接返回;如果不存在,则进行实例化。实例化可以通过构造函数、静态工厂方法或实例工厂方法来完成。
  • 属性注入:首先会检查是否有实例化的 Bean ,并且 Bean 信息中是否存在有属性值,如果存在实例化的 Bean ,并且 Bean 信息中存在有属性值的话,则进行属性注入。
  • Bean 初始化:完成属性注入后,Spring 会调用 Bean 的初始化方法。这可以是通过实现 InitializingBean 接口的 afterPropertiesSet 方法,或者是在 Bean 定义中指定 init-method 属性所指定的方法。这一步允许Bean进行必要的初始化操作,如资源加载、状态检查等。
  • 销毁回调函数注册:Spring 容器会为 bean 注册一个销毁回调,确保在容器关闭时能够正确地清理资源。
  • Bean 可用:经过上述步骤后,Bean 现在处于可用状态,可以被 Spring 容器管理,并可以注入到其他 Bean 中或提供给应用程序使用。
  • Bean 的销毁:当 Spring 容器关闭时,Spring 会调用 Bean 的销毁方法。

        在本文讲解 Spring Bean 的生命周期时提到过循环依赖,但是本文并没有讲解什么是循环依赖,循环依赖又该如何解决,而这个问题会在下一篇文章中进行详细的讲解。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值