【Spring_01】Bean的生命周期
本文主要有以下内容:
- Bean的生命周期
故事从一道美味的外卖说起:
买菜
天微微亮、勤奋的我就去菜市场和菜贩子斗智斗勇、争取拿到最新鲜的肉和蔬菜、做出最美味可口的菜肴以卷死附近的其他商家。经过一番唇枪舌战之后。我终于选出了满意的菜、回到店里开始处理。
择菜
起了个大早、上了个大当、原以为趁着人少我可以选出一些好菜、结果这些菜贩子趁着天还不咋亮、欺负由于多年敲代码导致视力老眼昏花的我、塞了一些不新鲜的配菜在我的菜篮子里面!真是一个奸商、要是我的店倒闭了就有这部分奸商的责任!说好的人与人之间的信任呢?
为了让我的顾客吃到新鲜美味的菜肴、虽然被菜贩子坑了但我还是一个踏踏实实做生意的人、于是乎我把不新鲜的菜丢到、重新购置了一部分菜、以备不时之需。
按照店里菜单上的菜品、将各种菜品的原材料备好、土豆切成丝、肉是肉片各准备一部分、切点回锅肉。就开始等待客户从美团上下单了。
对应实例化之前的代码
炒菜
在早上11点10分左右、接到今天的第一单、红烧肉。接到第一单自然是开心的。
起锅开火、热锅凉油、先把锅润一遍、等到差不多的时候倒出油、将事先切成小块且已焯水的精品五花肉放入锅中、煎至肉块上出现金黄色、用勺子盛出多余的油之后、进行下一步工作。
调味上色
肉已经煎得差不多了,放豆瓣酱炒出红油、放入干海椒、八角、老抽上色、一丢丢盐、以及事先炒好的糖色和山楂片、加热水大火烧开、小火慢炖二十分钟后、加入土豆块炖二十分钟之后大火收汁。
起锅装盘
在完成上述的操作之后、将菜品放入打包盒、贴上密封条、加入打包的袋子里面、放入好评返现券。
呼唤骑手
将打包好的菜放在指定的位置等待骑手取餐送货、至此一个外卖就做好了、当外卖送到客户手里时、被他吃掉之后、一个bean的生命周期也就结束了!
惊不惊喜?意不意外?
接下来就来来好好捋捋这个bean
的生命周期!
bean的生命周期总结
学习 Spring
的过程当中、我们肯定会会知道通过 xml
方式去配置一个bean
、也会了解IOC
容器等基本常识概念。我们知道配置的bean
(不管是xml
方式、还是注解@bean、@Service、@Controller
)会被IOC
容器创建且管理。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.supersist.spring.tutorial" />
<bean name="supersist" class="com.supersist.spring.tutorial.domain.User" init-method="doInit" destroy-method="doDestroy">
<property name="age" value="100"/>
<property name="name" value="壹贰是只猫"/>
</bean>
</beans>
那必然就会有一个地方装载着这些数据的原始信息。这个地方就是我们用来装菜的菜蓝子。
菜市场理解为IOC容器初始化之后、可对应BeanFactoryPostProcessor的代码。
菜篮子里面的菜就是我们的原始信息、不同的蔬菜相互组合就成了菜单上的菜。如果将菜单上的菜比喻成一个Bean的话、那么这道菜的所需要的原材料以及其他信息组成了BeanDefinition
因此如果要修改一个Bean
的信息就可以通过修改BeanDefinition
的值方式去修改。这一步就对应了择菜阶段。【实例化之前的准备】
BeanDefinition
包含了 bean 的各种属性信息,如类名、作用域、初始化方法、销毁方法、构造器参数、属性值等。
炒菜之前的洗菜阶段可对应InstantiationAwareBeanPostProcessor中的postProcessBeforeInstantiation方法。
炒菜阶段:这个阶段就是实例化的过程、即调用实体类的构造函数的过程。【实例化】
- 肉下锅之后会煎至金黄再放其他调味品【实例化之后的阶段】
调味上色:这一步可以分为两个阶段
- 备料阶段:准备好干辣椒、糖色、检查老抽、生抽等这一段。【属性注入前的准备】
- 下锅和肉炒的阶段【属性注入这一阶段】
起锅装盘:不管点什么外卖、商家的打包盒上都会有商家相关的信息、如店名、下单小票等。
- 实际上这一阶段就是对应【Aware】接口这一部分的回调
- setBeanName
- setBeanFactory
- setApplicationContext
在上述步骤完成之后、出餐会做一些额外的处理、比如添加餐具、添加一些饮料。出餐前的最后初始化阶段
- 这一部分对应的就是初始化这一阶段
骑手拿到餐之后、稍微检查一下、这就是初始化之后的调用阶段。客户签收之后就是使用阶段、客户处理掉这个外卖的时候就是销毁阶段。
如上所述生命周期可以分为如下几个阶段:
- 实例化
- 实例化之前阶段
- 实例化
- 实例化之后的阶段
- 属性注入
- 属性注入前的阶段
- 属性注入
- 初始化
- 初始化之前的调用
- 接口的初始化方法
- 手动指定的初始化方法
- 初始化之后的回调
- 使用
- 销毁
文字很抽象、用下图总结说明。从上往下、从左到右
图片说明:
BeanFactoryPostProcessor
: 是一个在 Spring 容器标准初始化之后调用的回调接口,可以在此接口中的方法修改BeanDefinition。
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MyBeanFactoryPostProcessor.class);
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
throws BeansException {
log.info("1.execute BeanFactoryPostProcessor#postProcessBeanFactory");
// 可以在这里修改BeanDefinition的信息
BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("supersist");
}
}
InstantiationBeanAwarePostProcessor:该接口是BeanPostProcessor接口的一个子接口、其中有三个方法、对每一个bean都起作用。
postProcessBeforeInstantiation()
:这个方法在所有Bean的实例化之前调用。可以在此方法修改属性注入的值postProcessAfterInstantiation()
:这个方法在所有Bean实例化之后调用。返回true or false决定是否进行属性填充postProcessProperties()
:在属性填充之前调用,可以修改属性值
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
log.info("2.execute InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation for {}", beanName);
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("4.实例化之后调用");
log.info("4.execute InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation for {}", beanName);
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("5.属性填充之前调用-修改注入的属性");
log.info("5.execute InstantiationAwareBeanPostProcessor#postProcessProperties for {}",pvs.getPropertyValues());
log.info("5.execute InstantiationAwareBeanPostProcessor#postProcessProperties for {}", beanName);
if ("supersist".equals(beanName)) {
System.out.println("Properties for bean 'supersist':");
MutablePropertyValues mutablePropertyValues = (MutablePropertyValues) pvs;
mutablePropertyValues.getPropertyValueList().forEach(propertyValue -> {
System.out.println("Property name: " + propertyValue.getName() + ", value: " + propertyValue.getValue());
});
mutablePropertyValues.addPropertyValue(new PropertyValue("name", "Updated Name"));
mutablePropertyValues.addPropertyValue(new PropertyValue("age", 40));
System.out.println("Modified properties for bean 'supersist':");
mutablePropertyValues.getPropertyValueList().forEach(propertyValue -> {
System.out.println("Property name: " + propertyValue.getName() + ", value: " + propertyValue.getValue());
});
return mutablePropertyValues;
}
return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
}
}
如果实体类实现了如下接口:
BeanNameAware
: 则属性填充后会调用setBeanName()
BeanFactoryAware
:则调用setBeanFactory()
ApplicationContextAware
:则调用setApplicationContextAware()
BeanPostProcessor
:此接口定义了初始化前后的回调函数、针对所有的Bean
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//log.info("10.初始化之前调用");
log.info("10.execute BeanPostProcessor#postProcessBeforeInitialization for {}", beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("13:初始化之后调用");
log.info("13.execute BeanPostProcessor#postProcessAfterInitialization for {}", beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
初始化执行顺序如下:
InitialzingBean
:如果实现了此接口、则调用afterPropertiesSet()
如果在xml配置中指定了初始化方法:则调用
init-method="doInit"
此方法
上述方法执行完毕之后、就会回调执行postProcessAfterInitialization
此方法。
接着被使用阶段被销毁
如果实体类实现了DisposableBean
、且指定了destory
方法则执行指定的destroy方法
@Override
public void destroy() throws Exception {
log.info("execute DisposableBean#destroy");
}
public void doDestroy() {
log.info("14.销毁");
log.info("execute User#doDestroy");
}
主类:
public static void main(String[] args) {
log.info("Init application context");
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
User user = (User) context.getBean("supersist");
log.info(user.toString());
log.info("Shutdown application context");
context.close();
}
配置的xml文件见最上面。
运行结果如下图:
参考资料:
转载自:https://juejin.cn/post/7398150089556721676