1. 简介
Spring框架的生命周期管理是一个核心功能,它提供了对bean的创建、配置、初始化、使用和销毁过程的控制。以下是为什么需要Spring生命周期的几个关键原因:
-
控制Bean的创建和初始化: Spring允许开发者通过生命周期接口(如
InitializingBean
和DisposableBean
)和注解(如@PostConstruct
和@PreDestroy
)来插入自定义的初始化和销毁逻辑。这使得开发者可以在Spring容器管理bean的生命周期中的特定点执行代码。 -
保证Bean的状态一致性: 通过Spring生命周期管理,可以确保bean在被使用之前已经完全初始化,并且在销毁前已经清理了资源。这有助于保持应用程序的状态一致性和稳定性。
-
增强配置的灵活性: Spring生命周期允许开发者在bean创建过程中的不同阶段进行配置,例如在
BeanPostProcessor
中可以修改bean的属性或者行为,这提供了比传统XML配置更高的灵活性和可扩展性。 -
实现IoC容器的自动装配: Spring的生命周期管理是实现其依赖注入(IoC)功能的基础。Spring容器负责创建bean、解析依赖关系,并在适当的时机将依赖关系注入到bean中。
-
提供AOP(面向切面编程)的支持: Spring的生命周期管理与AOP紧密集成,允许开发者在不修改业务逻辑代码的情况下,通过切面来横切关注点(如日志、事务管理等)。
-
管理资源和依赖关系: 在bean的生命周期中,Spring可以管理资源(如数据库连接、文件句柄等)和bean之间的依赖关系,确保资源在不再需要时被释放,依赖关系被正确解析。
-
提高代码的可测试性: Spring生命周期管理使得单元测试变得更加容易。开发者可以通过编程方式控制bean的生命周期,从而在测试环境中模拟bean的行为。
-
实现应用程序的优雅关闭: 通过
@PreDestroy
注解或DisposableBean
接口,Spring可以在容器关闭时执行清理逻辑,如关闭数据库连接、释放线程资源等,实现应用程序的优雅关闭。 -
解耦业务逻辑和基础设施代码: Spring生命周期管理帮助将业务逻辑与基础设施代码(如事务管理、安全性、日志记录等)解耦,使得业务逻辑更加清晰和专注。
-
支持事件驱动编程: Spring的生命周期管理支持事件发布和监听,允许开发者在bean的生命周期中的特定点发布事件,其他组件可以监听这些事件并作出响应。
2. 流程图
Spring Bean生命周期包含了实例化、属性赋值、初始化-前置、初始化、初始化-后置、使用等阶段。
-
实例化(Instantiation):
-
Spring容器使用Bean的构造器、工厂方法或父容器获取Bean的实例。
-
-
属性赋值(Property Population):
-
Spring容器为Bean的属性设置值,这些值来自配置文件、注解或代码中的显式值。
-
-
BeanNameAware、BeanFactoryAware:
-
如果Bean实现了
BeanNameAware
接口,Spring将调用setBeanName
方法,传入Bean的名称。 -
如果Bean实现了
BeanFactoryAware
接口,Spring将调用setBeanFactory
方法,传入BeanFactory
的实例。
-
-
BeanPostProcessor前置处理(BeanPostProcessor Pre-Processing):
-
如果有
BeanPostProcessor
实现,Spring将调用postProcessBeforeInitialization
方法。
-
-
初始化(Initialization):
-
如果Bean实现了
InitializingBean
接口,Spring将调用afterPropertiesSet
方法。 -
如果Bean定义了
init-method
,Spring将调用配置中指定的初始化方法。
-
-
BeanPostProcessor后置处理(BeanPostProcessor Post-Processing):
-
如果有
BeanPostProcessor
实现,Spring将调用postProcessAfterInitialization
方法。
-
-
使用(Usage):
-
完成初始化的Bean将被放入Spring容器中,应用程序可以通过容器获取Bean并使用它。
-
-
销毁(Destruction):
-
当容器关闭时,如果Bean实现了
DisposableBean
接口,Spring将调用destroy
方法。 -
如果Bean定义了
destroy-method
,Spring将调用配置中指定的销毁方法。
-
-
注册关闭钩子(Register Destruction Hooks):
-
Spring注册JVM关闭钩子(如果Bean实现了
DisposableBean
接口或定义了destroy-method
)。
-
-
容器关闭(Container Shutdown):
-
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");
}
}
-
BeanDefinitionRegistryPostProcessor:
-
实现了
BeanDefinitionRegistryPostProcessor
接口的Bean可以修改Bean的定义(BeanDefinition
)。 -
这个方法在Bean定义已经加载到注册表(
BeanDefinitionRegistry
)之后、Bean定义解析完成之前执行。 -
因此,
BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法在Bean的实例化之前执行,且在BeanFactoryPostProcessor
的postProcessBeanFactory
方法之前执行。
-
-
BeanFactoryPostProcessor:
-
实现了
BeanFactoryPostProcessor
接口的Bean可以修改BeanFactory
本身,例如改变Bean的属性值、注册额外的Bean等。 -
postProcessBeanFactory
方法在Bean定义信息已经完全加载和解析之后、Bean实例化之前执行。 -
这意味着
BeanFactoryPostProcessor
的方法在Bean的实例化之前执行,但在BeanDefinitionRegistryPostProcessor
的方法之后。
-
总结来说,BeanDefinitionRegistryPostProcessor
和 BeanFactoryPostProcessor
中的方法都是在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