Spring Bean生命周期

1. 简介

        Spring框架的生命周期管理是一个核心功能,它提供了对bean的创建、配置、初始化、使用和销毁过程的控制。以下是为什么需要Spring生命周期的几个关键原因:

  1. 控制Bean的创建和初始化: Spring允许开发者通过生命周期接口(如InitializingBeanDisposableBean)和注解(如@PostConstruct@PreDestroy)来插入自定义的初始化和销毁逻辑。这使得开发者可以在Spring容器管理bean的生命周期中的特定点执行代码。

  2. 保证Bean的状态一致性: 通过Spring生命周期管理,可以确保bean在被使用之前已经完全初始化,并且在销毁前已经清理了资源。这有助于保持应用程序的状态一致性和稳定性。

  3. 增强配置的灵活性: Spring生命周期允许开发者在bean创建过程中的不同阶段进行配置,例如在BeanPostProcessor中可以修改bean的属性或者行为,这提供了比传统XML配置更高的灵活性和可扩展性。

  4. 实现IoC容器的自动装配: Spring的生命周期管理是实现其依赖注入(IoC)功能的基础。Spring容器负责创建bean、解析依赖关系,并在适当的时机将依赖关系注入到bean中。

  5. 提供AOP(面向切面编程)的支持: Spring的生命周期管理与AOP紧密集成,允许开发者在不修改业务逻辑代码的情况下,通过切面来横切关注点(如日志、事务管理等)。

  6. 管理资源和依赖关系: 在bean的生命周期中,Spring可以管理资源(如数据库连接、文件句柄等)和bean之间的依赖关系,确保资源在不再需要时被释放,依赖关系被正确解析。

  7. 提高代码的可测试性: Spring生命周期管理使得单元测试变得更加容易。开发者可以通过编程方式控制bean的生命周期,从而在测试环境中模拟bean的行为。

  8. 实现应用程序的优雅关闭: 通过@PreDestroy注解或DisposableBean接口,Spring可以在容器关闭时执行清理逻辑,如关闭数据库连接、释放线程资源等,实现应用程序的优雅关闭。

  9. 解耦业务逻辑和基础设施代码: Spring生命周期管理帮助将业务逻辑与基础设施代码(如事务管理、安全性、日志记录等)解耦,使得业务逻辑更加清晰和专注。

  10. 支持事件驱动编程: Spring的生命周期管理支持事件发布和监听,允许开发者在bean的生命周期中的特定点发布事件,其他组件可以监听这些事件并作出响应。

2. 流程图

        Spring Bean生命周期包含了实例化、属性赋值、初始化-前置、初始化、初始化-后置、使用等阶段。

  1. 实例化(Instantiation)

    1. Spring容器使用Bean的构造器、工厂方法或父容器获取Bean的实例。

  2. 属性赋值(Property Population)

    1. Spring容器为Bean的属性设置值,这些值来自配置文件、注解或代码中的显式值。

  3. BeanNameAware、BeanFactoryAware

    1. 如果Bean实现了BeanNameAware接口,Spring将调用setBeanName方法,传入Bean的名称。

    2. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory方法,传入BeanFactory的实例。

  4. BeanPostProcessor前置处理(BeanPostProcessor Pre-Processing)

    1. 如果有BeanPostProcessor实现,Spring将调用postProcessBeforeInitialization方法。

  5. 初始化(Initialization)

    1. 如果Bean实现了InitializingBean接口,Spring将调用afterPropertiesSet方法。

    2. 如果Bean定义了init-method,Spring将调用配置中指定的初始化方法。

  6. BeanPostProcessor后置处理(BeanPostProcessor Post-Processing)

    1. 如果有BeanPostProcessor实现,Spring将调用postProcessAfterInitialization方法。

  7. 使用(Usage)

    1. 完成初始化的Bean将被放入Spring容器中,应用程序可以通过容器获取Bean并使用它。

  8. 销毁(Destruction)

    1. 当容器关闭时,如果Bean实现了DisposableBean接口,Spring将调用destroy方法。

    2. 如果Bean定义了destroy-method,Spring将调用配置中指定的销毁方法。

  9. 注册关闭钩子(Register Destruction Hooks)

    1. Spring注册JVM关闭钩子(如果Bean实现了DisposableBean接口或定义了destroy-method)。

  10. 容器关闭(Container Shutdown)

    1. Spring容器关闭,触发所有注册的销毁回调。

3. 示例代码

3.1 添加依赖

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.7.12</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>2.7.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.26</version>
    </dependency>
</dependencies>

3.2 BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor

        自定义类实现这两个接口,重写postProcessBeanDefinitionRegistry()方法和postProcessBeanFactory()方法。

未被Spring管理的bean

package com.xiaokai.service;

import lombok.extern.slf4j.Slf4j;

/**
 * Author:yang
 * Date:2024-10-29 13:34
 */
@Slf4j
public class DynamicBean {

    public void sayHello(){
        log.info("Hello, I am a dynamic bean!");
    }
}

通过postProcessBeanDefinitionRegistry注入到Spring中

package com.xiaokai.config;

import com.xiaokai.service.DynamicBean;
import com.xiaokai.service.UserService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

/**
 * Author:yang
 * Date:2024-10-29 11:32
 */
@Component
public class CustomBeanProcessor implements BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor {

    /**
     * 在BeanDefinitionRegistryPostProcessor接口中,我们可以对BeanDefinitionRegistry进行一些自定义的操作,比如注册BeanDefinition、移除BeanDefinition等。
     * 这个方法允许开发者动态注册新的Bean定义或修改现有的Bean定义。
     * 它通常在postProcessBeanFactory方法之前被调用,因此可以注册新的Bean定义,这些Bean定义随后可以在postProcessBeanFactory中被处理。
     * 这个方法只在实现了BeanDefinitionRegistryPostProcessor接口的BeanFactoryPostProcessor实现类中被调用。
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 定义一个BeanDefinition
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DynamicBean.class);
        beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        // 注册一个BeanDefinition
        beanDefinitionRegistry.registerBeanDefinition("dynamicBean", beanDefinition);

    }

    /**
     * 在BeanFactoryPostProcessor接口中,我们可以对ConfigurableListableBeanFactory进行一些自定义的操作,比如注册BeanPostProcessor、设置BeanFactoryPostProcessor等。
     * 这个方法允许开发者对BeanFactory进行一些自定义的配置,比如设置BeanFactoryPostProcessor、BeanPostProcessor等。
     * 它通常在postProcessBeanDefinitionRegistry方法之后被调用,因此可以注册BeanFactoryPostProcessor、BeanPostProcessor等,这些BeanFactoryPostProcessor、BeanPostProcessor等可以对BeanFactory进行一些自定义的配置。
     * 这个方法只在实现了BeanFactoryPostProcessor接口的BeanFactoryPostProcessor实现类中被调用。
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        // 修改UserService的name属性,这样做会预实例化---影响bean的生命周期
        //UserService userService = configurableListableBeanFactory.getBean(UserService.class);
        //userService.setName("xiaokai");

        BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("userService");
        beanDefinition.getPropertyValues().addPropertyValue("name", "xiaokai");
    }
}
  1. BeanDefinitionRegistryPostProcessor:

    1. 实现了 BeanDefinitionRegistryPostProcessor 接口的Bean可以修改Bean的定义(BeanDefinition)。

    2. 这个方法在Bean定义已经加载到注册表(BeanDefinitionRegistry)之后、Bean定义解析完成之前执行。

    3. 因此,BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry 方法在Bean的实例化之前执行,且在 BeanFactoryPostProcessorpostProcessBeanFactory 方法之前执行。

  2. BeanFactoryPostProcessor:

    1. 实现了 BeanFactoryPostProcessor 接口的Bean可以修改 BeanFactory 本身,例如改变Bean的属性值、注册额外的Bean等。

    2. postProcessBeanFactory 方法在Bean定义信息已经完全加载和解析之后、Bean实例化之前执行。

    3. 这意味着 BeanFactoryPostProcessor 的方法在Bean的实例化之前执行,但在 BeanDefinitionRegistryPostProcessor 的方法之后。

        总结来说,BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 中的方法都是在Bean实例化之前执行的,但 BeanDefinitionRegistryPostProcessor 的方法执行得更早,它允许修改Bean的定义信息,而 BeanFactoryPostProcessor 的方法则在Bean定义信息处理完成后、Bean实例化之前执行,允许修改Bean工厂的配置。这两个接口提供了在Bean生命周期的早期阶段进行自定义配置和修改的机会。

测试结果:

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ApplicationTest {


    @Autowired
    private UserService userService;

    @Autowired
    private DynamicBean dynamicBean;

    @Test
    public void test(){
        log.info("userService name:{}",userService.getName());
    }

    @Test
    public void testDynamicBean(){
        dynamicBean.sayHello();
    }
}

service.DynamicBean          : Hello, I am a dynamic bean!
xiaokai.ApplicationTest      : userService name:xiaokai

        没有添加相应注解的bean也通过postProcessBeanDefinitionRegistry注入到Spring容器中,同时通过postProcessBeanFactory给另外一个bean中的属性赋值。

3.3 BeanNameAware、BeanFactoryAware

package com.xiaokai.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;

/**
 * Author:yang
 * Date:2024-10-29 13:58
 */
@Component("xiaoKaiBean")
@Slf4j
public class CustomBean implements BeanNameAware, BeanFactoryAware {

    /**
     * beanFactory中存在了全部的bean对象,可以通过getBean()方法获取到需要的bean对象
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        DynamicBean bean = beanFactory.getBean(DynamicBean.class);
        bean.sayHello();
    }

    /**
     * 获取当前到bean的名字
     * @param s
     */
    @Override
    public void setBeanName(String s) {
        log.info("BeanNameAware: Bean name is " + s);
    }
}

启动程序

2024-10-29 14:34:12.161  INFO 15996 --- [  main] com.xiaokai.service.CustomBean : 
BeanNameAware: Bean name is xiaoKaiBean
2024-10-29 14:34:12.162  INFO 15996 --- [  main] com.xiaokai.service.DynamicBean: 
Hello, I am a dynamic bean!

3.4 BeanPostProcessor前置处理、后置处理

        使用自定义注解使用中的示例代码,具体测试结果可以在自定义注解使用

package com.xiaokai.beanpost;

import com.xiaokai.aspect.config.anno.CustomLogging;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Author:yang
 * Date:2024-10-28 13:36
 * Description:自定义BeanPostProcessor重写bean初始化前、后置处理器
 */
@Component
@Slf4j
public class CustomLoggingPostProcessor implements BeanPostProcessor {

    // 记录下来可以多次使用
    public final static Map<String, List<Method>> annotatedMethods = new HashMap<>();

    /**
     * 重写bean初始化前置处理器---不做任何处理
     * 检查Bean的属性值是否符合预期。
     * 修改Bean的状态或行为。
     * 记录Bean的初始化过程。
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }


    /**
     * 重写bean初始化后置处理器---判断方法上是否有自定义注解,做相应逻辑处理
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 获取bean--->这个获取的bean是AOP之后代理对象,方法上是没有注解的,这种方法不可行
        //Class<?> aClass = bean.getClass();
        // 判断类上是否有自定义注解
        //if (targetClass.isAnnotationPresent(CustomLogging.class)) {}

        // 获取原始的bean对象
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
        // 判断方法上是否有自定义注解
        Method[] methods = targetClass.getMethods();
        ArrayList<Method> list = new ArrayList<>();
        for (Method method : targetClass.getDeclaredMethods()) {
            if (method.isAnnotationPresent(CustomLogging.class)) {
                log.info("Method {}.{} has custom logging annotation", targetClass.getName(), method.getName());
                // 自定义逻辑处理
                // 记录下来可以多次使用
                list.add(method);
            }
        }
        annotatedMethods.put(beanName, list);

        return bean;
    }
}

其余的都比较好理解,就不意义叙述了

不积跬步,无以至千里 --- xiaokai

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值