Spring Bean生命周期详解

简介: 之前我们在总结Spring扩展点:后置处理器时谈到了Spring Bean的生命周期和其对Spring框架原理理解的重要性,所以接下来我们就来分析一下Bean生命周期的整体流程。首先Bean就是一些Java对象,只不过这些Bean不是我们主动new出来的,而是交个Spring IOC容器创建并管理的,因此Bean的生命周期受Spring IOC容器控制

1.概述

之前我们在总结Spring扩展点:后置处理器时谈到了Spring Bean的生命周期和其对Spring框架原理理解的重要性,所以接下来我们就来分析一下Bean生命周期的整体流程。首先Bean就是一些Java对象,只不过这些Bean不是我们主动new出来的,而是交个Spring IOC容器创建并管理的,因此Bean的生命周期受Spring IOC容器控制,Bean生命周期大致分为以下几个阶段:

  • Bean的实例化(Instantiation):Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化
  • Bean的属性赋值(Populate):Bean实例化之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充,Bean的属性赋值就是指 Spring 容器根据BeanDefinition中属性配置的属性值注入到 Bean 对象中的过程。
  • Bean的初始化(Initialization):对Bean实例的属性进行填充完之后还需要执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,并且Spring高频面试题Bean的循环引用问题也是在这个阶段体现的;

  • Bean的使用阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期,接下来Bean就可以被随心所欲地使用了。

  • Bean的销毁(Destruction):Bean 的销毁是指 Spring 容器在关闭时,执行一些清理操作的过程。在 Spring 容器中, Bean 的销毁方式有两种:销毁方法destroy-method和 DisposableBean 接口。

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

2.Bean生命周期详解和使用案例

这里我先纠正一下在Spring扩展点后置处理器总结的描述:之前说BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor这三个后置处理器的调用时机都在Spring Bean生命周期中是不严谨的,按照上面我们对Bean生命周期的阶段划分,只有BeanPostProcessor作用于Bean的生命周期中,而BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor是针对BeanDefinition的,所以不属于Bean的生命周期中。

BeanPostProcessor在Bean生命周期的体现如下图所示:

Bean的生命周期和人的一生一样都会经历从出生到死亡,中间是一个漫长且复杂的过程,接下来我们就来整体分析一下Bean生命周期的核心流程和相关接口回调方法的调用时机,同时这里想强调一下Bean的生命周期也是面试的高频考点,对核心流程务必要掌握清楚,这里用一张流程图进行详述展示,是重点、重点、重点

根据上面的Bean生命周期核心流程做如下代码演示示例:

Bean定义:

@Data
@AllArgsConstructor
public class Boo implements InitializingBean, DisposableBean, BeanNameAware {
   
   
    private Long id;
    private String name;

    public Boo() {
   
   
        System.out.println("boo实例化构造方法执行了...");
    }

    @PostConstruct
    public void initMethod() {
   
   
        System.out.println("boo执行初始化init()方法了...");
    }

    @PreDestroy
    public void destroyMethod() {
   
   
        System.out.println("boo执行初始化destroy()方法了...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
   
   
        System.out.println("boo执行InitializingBean的afterPropertiesSet()方法了...");
    }

    @Override
    public void destroy() throws Exception {
   
   
        System.out.println("boo执行DisposableBean的destroy()方法了...");
    }

    @Override
    public void setBeanName(String name) {
   
   
        System.out.println("boo执行BeanNameAware的setBeanName()方法了...");
    }
}

实现InstantiationAwareBeanPostProcessor:

@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
   
   
    @Override
    public Object postProcessBeforeInstantiation(Class<?> BeanClass, String BeanName) throws BeansException {
   
   
        System.out.println("InstantiationAwareBeanPostProcessor的before()执行了...." + BeanName);
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object Bean, String BeanName) throws BeansException {
   
   
        System.out.println("InstantiationAwareBeanPostProcessor的after()执行了...." + BeanName);
        return false;
    }
}

实现BeanPostProcessor:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
   
   
    @Override
    public Object postProcessBeforeInitialization(Object Bean, String BeanName) throws BeansException {
   
   
        System.out.println("BeanPostProcessor的before()执行了...." + BeanName);
        return Bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object Bean, String BeanName) throws BeansException {
   
   
        System.out.println("BeanPostProcessor的after()执行了...."+ BeanName);
        return Bean;
    }
}

执行下面的配置类测试方法:

@ComponentScan(basePackages = {
   
   "com.shepherd.common.config"})
@Configuration
public class MyConfig {
   
   

    @Bean
    public Boo boo() {
   
   
        return new Boo();
    }

    public static void main(String[] args) {
   
   

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        String[] BeanDefinitionNames = applicationContext.getBeanDefinitionNames();
        // 遍历Spring容器中的BeanName
        for (String BeanDefinitionName : BeanDefinitionNames) {
   
   
            System.out.println(BeanDefinitionName);
        }
        // 这里调用的applicationContext的close()触发Bean的销毁回调方法
        applicationContext.close();
    }
}

名为boo的Bean相关运行结果如下:

InstantiationAwareBeanPostProcessor的before()执行了....boo
boo实例化构造方法执行了...
InstantiationAwareBeanPostProcessor的after()执行了....boo
boo执行BeanNameAware的setBeanName()方法了...
BeanPostProcessor的before()执行了....boo
boo执行初始化init()方法了...
boo执行InitializingBean的afterPropertiesSet()方法了...
BeanPostProcessor的after()执行了....boo
......
boo执行初始化destroy()方法了...
boo执行DisposableBean的destroy()方法了...

根据控制台打印结果可以boo的相关方法执行顺序严格遵从上面流程图,同时当我们执行容器applicationContext的关闭方法close()会触发调用bean的销毁回调方法。

3.浅析Bean生命周期源码实现

DefaultListableBeanFactory是Spring IOC的Bean工厂的一个默认实现,IOC大部分核心逻辑实现都在这里,可关注。Bean生命周期就是创建Bean的过程,这里我们就不在拐弯抹角兜圈子,直接来到DefaultListableBeanFactory继承的AbstractAutowireCapableBeanFactory#doCreateBean()方法,之前说过在Spring框架中以do开头的方法都是核心逻辑实现所在

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

        // Instantiate the Bean.
        // BeanWrapper 是对 Bean 的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装 Bean 的属性描述器
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
   
   
            // <1> 单例模型,则从未完成的 FactoryBean 缓存中删除
            instanceWrapper = this.factoryBeanInstanceCache.remove(BeanName);
        }
        if (instanceWrapper == null) {
   
   
            // <2> 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
            instanceWrapper = createBeanInstance(BeanName, mbd, args);
        }
        // 包装的实例对象
        Object Bean = instanceWrapper.getWrappedInstance();
        // 包装的实例class类型
        Class<?> BeanType = instanceWrapper.getWrappedClass();
        if (BeanType != NullBean.class) {
   
   
            mbd.resolvedTargetType = BeanType;
        }

        // Allow post-processors to modify the merged Bean definition.
        // <3> 判断是否有后置处理
        // 如果有后置处理,则允许后置处理修改 BeanDefinition
        synchronized (mbd.postProcessingLock) {
   
   
            if (!mbd.postProcessed) {
   
   
                try {
   
   
                    applyMergedBeanDefinitionPostProcessors(mbd, BeanType, BeanName);
                }
                catch (Throwable ex) {
   
   
                    throw new BeanCreationException(mbd.getResourceDescription(), BeanName,
                            "Post-processing of merged Bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        // <4> 解决单例模式的循环依赖
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(BeanName));
        if (earlySingletonExposure) {
   
   
            if (logger.isTraceEnabled()) {
   
   
                logger.trace("Eagerly caching Bean '" + BeanName +
                        "' to allow for resolving potential circular references");
            }
            // 提前将创建的 Bean 实例加入到 singletonFactories 中
            // 这里是为了后期避免循环依赖
            addSingletonFactory(BeanName, () -> getEarlyBeanReference(BeanName, mbd, Bean));
        }

        // Initialize the Bean instance.
        // 开始初始化 Bean 实例对象
        Object exposedObject = Bean;
        try {
   
   
            // <5> 对 Bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 Bean 的属性
            // 则会递归初始依赖 Bean
            populateBean(BeanName, mbd, instanceWrapper);
            // <6> 调用初始化方法
            exposedObject = initializeBean(BeanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
   
   
            if (ex instanceof BeanCreationException && BeanName.equals(((BeanCreationException) ex).getBeanName())) {
   
   
                throw (BeanCreationException) ex;
            }
            else {
   
   
                throw new BeanCreationException(
                        mbd.getResourceDescription(), BeanName, "Initialization of Bean failed", ex);
            }
        }

        // <7> 循环依赖处理
        if (earlySingletonExposure) {
   
   
            // 获取 earlySingletonReference
            Object earlySingletonReference = getSingleton(BeanName, false);
            // 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
            if (earlySingletonReference != null) {
   
   
                // 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
                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(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.");
                    }
                }
            }
        }

        // Register Bean as disposable.
        try {
   
   
            // <8> 注册 Bean的销毁逻辑
            registerDisposableBeanIfNecessary(BeanName, Bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
   
   
            throw new BeanCreationException(
                    mbd.getResourceDescription(), BeanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

由上面代码可知,Bean的创建过程核心步骤如下:

  • createBeanInstance(BeanName, mbd, args) 进行Bean的实例化
  • populateBean(BeanName, mbd, instanceWrapper)进行Bean的属性填充赋值
  • initializeBean(BeanName, exposedObject, mbd)处理Bean初始化之后的各种回调事件
  • registerDisposableBeanIfNecessary(BeanName, Bean, mbd)注册Bean的销毁接口
  • 解决创建Bean过程中的循环依赖,Spring使用三级缓存解决循环依赖,这也是一个重要的知识点,这里不详细阐述,后面会安排

接下来我们就来看看和Bean初始化阶段相关各种回调事件执行方法#initializeBean(),分析一下上面流程图的执行顺序是怎么实现的。

protected Object initializeBean(final String BeanName, final Object Bean, RootBeanDefinition mbd) {
   
   
        if (System.getSecurityManager() != null) {
   
   
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
   
   
                @Override
                public Object run() {
   
   
                    invokeAwareMethods(BeanName, Bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
   
   
            // 涉及到的回调接口点进去一目了然,代码都是自解释的
            // BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
            invokeAwareMethods(BeanName, Bean);
        }

        Object wrappedBean = Bean;
        if (mbd == null || !mbd.isSynthetic()) {
   
   
            // BeanPostProcessor 的 postProcessBeforeInitialization 回调
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, BeanName);
        }

        try {
   
   
            // init-methods
            // 或者是实现了InitializingBean接口,会调用afterPropertiesSet() 方法
            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 回调
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, BeanName);
        }
        return wrappedBean;
    }

至于Bean的销毁流程与Bean初始化类似,从上面的使用示例中看可以得出当容器关闭时,才会对Bean销毁方法进行调用。销毁过程是这样的。顺着close()-> doClose() -> destroyBeans() -> destroySingletons() -> destroySingleton() -> destroyBean() -> Bean.destroy(),会看到最终调用Bean的销毁方法。这里就不在展示源码细节啦,有兴趣的话自行去调试查看了解

4.总结

以上全部就是对Spring Bean生命周期的全面总结, Spring 的 Bean 容器机制是非常强大的,它可以帮助我们轻松地管理 Bean 对象,并且提供了丰富的生命周期回调方法,允许我们在 Bean 的生命周期中执行自己的特定操作,这对于我们平时工作使用中进行增强扩展至关重要,因此掌握Bean的生命周期是必须的。

目录
相关文章
|
3月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
15天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
70 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
2月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
215 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
1月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
223 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
2月前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
83 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
40 1
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
88 1