目录
一、Spring IOC
1.1 Spring IOC 的加载过程
二、Spring Bean 生命周期
2.1 实例化前置
2.2 实例化后置
2.3 属性赋值
2.4 初始化前置
2.5 初始化
2.6 初始化后置
2.7 Bean 销毁
Spring 是一个开源的企业级Java应用程序框架,它简化了企业级应用程序开发,同时促进了松耦合、面向切面编程(AOP)、声明式事务管理以及基于Java EE平台的最佳实践。
Spring 已经成为现代 Java 企业级应用开发的事实标准框架之一。今天就来了解下 Spring Bean的生命周期。
一、Spring IOC
Spring IOC 也叫控制反转或依赖注入,那谁控制谁呢?在以前,对象的创建销毁都是用户自己控制的,用了 IOC 之后对象的创建和销毁都交给了 Spring 容器来控制,用户不用管这些了,值管制业务需求就好。
为什么叫控制反转呢?既然有反转,应该有正转。正转就是对象去找实例,比如你 new 了一个对象,那这个对象就指向了对象实例。反转就是通过实例来找对象。具体来说就是先通过容器找到实例,然后通过实例找到对象。
1.1 Spring IOC 的加载过程
整个加载过程大致如图所示:
具体步骤如下:
1、首先,通过 BeandefinitionReader 读取执行的配置文件生成 bean 的信息,然后到完整的 Beandefinition 定义信息,注意,这里存储的事 Bean 的定义信息,包括:是否单例、是否懒加载、是否抽象等等信息。就像工厂生产产品一样,准备好了原材料,下一步就该生成了。
2、在生成完整的 Beandefinition 前,还可以通过 BeanFactoryPostProcessor 对 Beandefinition 进行增强,这个增强器可以设置多个。
/**
* 扩展方法--后置增强器(可修改bean的定义信息)
*/
@Component
public class ExtBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition service = beanFactory.getBeanDefinition("Service");
System.out.println("扩展方法--可进行修改beanDefinition的定义信息");
}
}
3、得到完整的 Beandefinition 后就可以创建对象了, 创建对象的过程称为 bean 的生命周,也就是从实例化到销毁的过程。
二、Spring Bean 生命周期
Spring Bean 的生命周期简单来说只有四个阶段:实例化(Instantiation)、属性赋值(Populate)、初始化(Initialiation)、销毁(Destruction),在这四个阶段中外加几个扩展点,就组成了完整的生命周期。
主要逻辑在doCreateBean()方法中,逻辑很清晰,就是顺序调用一下三个方法。这三个方法与三个生命周期阶段一一对应,非常重要。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化,通过反射实现
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
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.
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");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 属性注入,包含循环依赖
populateBean(beanName, mbd, instanceWrapper);
// 初始化
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);
}
}
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(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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
实例化前后的扩展通过 InstantiationAwareBeanPostprocessor 实现,初始化的前后扩展通过 BeanPostprocessor 实现,如下代码:
Component
public class InstantiationAwareBeanPostProcessorDemo implements InstantiationAwareBeanPostProcessor {
// 实例化前置
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("postProcessBeforeInstantiation被调用了----在对象实例化之前调用-----beanName:" + beanName);
// 默认什么都不做,返回null
return null;
}
// 实例化后置
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInstantiation被调用了---------beanName:" + beanName);
//默认返回true,什么也不做,继续下一步
return true;
}
// 属性修改
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
System.out.println("postProcessPropertyValues被调用了---------beanName:"+beanName);
// 此方法可对bean中的属性值进行、添加、修改、删除操作;
// 对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用,
return pvs;
}
}
2.1 实例化前置
实例化前置使用的是 postProcessBeforeInstantiation 方法,有两个参数,分别是beanClass 和 beanName,顾名思义,就是在对象实例化之前对 bean 对象的 class 信息进行修改或者扩展,以达到我们想要的功能,它的底层是动态代理 AOP 技术实现的;且是 bean 生命周期中最先执行的方法。
返回值是 Object 类型,这意味着我们可以返回任何类型的值,由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成对象的目标对象的实例,也就是说,如果返回了非空的值,那么以后我们需要用到这个bean的时候,拿到的就现在返回的对象了,也就不会去走第二步去实例化对象了。
然后就是执行对象实例化了,通过调用 doCreateBean 方法来实现。
2.2 实例化后置
实例化后置使用的是 postProcessAfterInstantiation 方法,这时实例已经创建,下一步就是属性赋值,相当于调用 set 方法,如果返回的是 false,意味着不会对该 bean 执行任何属性注入和其他初始化的逻辑。这种情况下,通常意味着开发者已经在该方法内部完成了所有必要的初始化工作,或者处于某种原因不让 Spring 容器继续初始化该 Bean。
如果该方法返回的是 true,那会继续执行后续的流程。
2.3 属性赋值
属性赋值是通过 AbstractAutowireCapableBeanFactory.populateBean() 方法进行的。主要负责将 Bean 定义中的属性注入到已经实例化的 Bean 中。主要包含了 Setter 方法注入、构造器注入、字段注入等功能。
2.4 初始化前置
通过 BeanPostProcessor.postProcessBeforeInitialization() 来实现,在每一个 Bean 初始化之前执行,具体是指在调用初始化方法或 @PostConstruct 注解的方法执行前去执行前置操作。
开发者可以根据业务需求,对特定的 Bean 在其初始化前做额外的增强功能,比如设置一些默认值、处理特殊的业务规则等。
2.5 初始化
Spring 初始化的方式有三种,分别是@PostConstruct、实现了 InitializingBean 接口、在注解 @Bean 中设置了 initMethod。
通过 @PostConstruct 初始化实现如下:
import javax.annotation.PostConstruct;
public class MyBean {
@PostConstruct
public void init() {
// 初始化逻辑
}
}
通过实现 InitializingBean 接口来初始化 Bean 时,需要重写 afterPropertiesSet 方法,Spring容器会在Bean实例化并设置好所有属性后调用该方法。
import org.springframework.beans.factory.InitializingBean;
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}
}
Java配置中的 @Bean
注解: 使用 @Bean
注解定义Bean时,可以指定 initMethod
属性来设置初始化方法。
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public MyBean myBean() {
return new MyBean();
}
}
// 对应的Java类
public class MyBean {
public void init() {
// 初始化逻辑
}
}
这些初始化方式的执行顺序大致为:
- @PostConstruct 注解的方法
- InitializingBean 接口的 afterPropertiesSet 方法
- init-method 指定的方法
2.6 初始化后置
通过调用 postProcessAfterInitialization 来实现初始化后置扩展,会在 Spring 容器完成对 Bean 的初始化之后,但在 Bean 交付给 Spring 容器进行使用之前执行。比如
- 对 Bean 的属性值进行最后的修改或补充设置
- 对 Bean 进行迭代增强,比如动态代理等
- 甚至是完全替换掉这个 Bean 实例
2.7 Bean 销毁
当Spring容器不再需要一个Bean或容器本身正在关闭时,会按照一定的顺序对Bean进行销毁。销毁的方式如下:
- 如果一个Bean实现了
org.springframework.beans.factory.DisposableBean
接口,那么在销毁阶段,Spring会调用其destroy()
方法。 - 若 Bean 中存在一个方法使用了
@PreDestroy
注解,那么在销毁 Bean 之前,Spring 会调用这个方法。 - 如果在 @Bean 注解中使用了
destroy-method
属性,销毁 Bean 时会调用该方法
总之,Spring Bean 的生命周期在保持基本的功能基础上,引入了诸多扩展点,为开发者提供了诸多便捷的功能,以实现更加灵活的定制化需求。
往期经典推荐:
Redis分布式锁:保障微服务架构下的并发控制与数据一致性实战指南-CSDN博客
探析Drools规则引擎的工作原理_规则引擎执行性能-CSDN博客
实时数据传输的新里程——Server-Sent Events(SSE)消息推送技术-CSDN博客
Spring循环依赖的成因与破局-CSDN博客
SpringBoot项目并发处理大揭秘,你知道它到底能应对多少请求洪峰?_一个springboot能支持多少并发-CSDN博客