参考文章:
https://blog.csdn.net/qq_23473123/article/details/76610052
https://www.cnblogs.com/zrtqsk/p/3735273.html
https://blog.csdn.net/w_linux/article/details/80086950
Spring容器介绍
在IoC容器启动之后,Spring加载分析XML配置信息解析,并将其封装到BeanDefinition对象中保存到Map<beanid,BeanDefinition>中,但是并不会马上就实例化相应的bean。此时容器仅仅拥有所有Bean的BeanDefinition(BeanDefinition:各个Bean的配置信息对象。是容器依赖某些工具加载的XML配置信息进行解析和分析,并将分析后的信息编组为相应的BeanDefinition中)。只有当getBean()调用时或被其他要实例化的Bean依赖注入时,才是有可能触发Bean实例化阶段的活动。
为什么说有可能触发Bean实例化阶段?因为当对应某个bean定义的getBean()方法第一次被调用时,不管是显示的还是隐式的,Bean实例化阶段才会被触发,第二次被调用则会直接返回容器缓存的第一次实例化完的对象实例(因为默认是singleton单例,当然,这里的情况prototype类型的bean除外)
各种生命周期接口分类
Spring框架提供丰富的接口和生命周期方法,使开发者在不修改Spirng框架的基础上,对Sping进行改造,影响执行流程。满足开闭原则
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
4、容器级工厂后处理器接口方法:这个包括了BeanFactoryPostProcessor、AspectJWeavingEnabler,、ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。在应用上下文装配配置文件之后立即调用。
容器级Bean:监控整个容器的其他Bean。实现此类接口的Bean在IoC容器启动BeanFactory实例化之后会立即实例化。此类型的Bean理论上来说容器中相同功能的存在一个Bean即可。
下图可见:Spring Bean的完整生命周期从创建Spring-IoC容器开始,直到最终Spring容器销毁Bean
红色的容器级生命周期接口的Bean会在其他Bean实例化之前实例化。因为他们的功能是监控整个容器的Bean。
绿色为Bean级生命周期接口
蓝色为Bean自身的方法
各个接口详细使用样例:https://blog.csdn.net/qq_23473123/article/details/76610052
现在开始初始化容器
2014-5-18 15:46:20 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@19a0c7c: startup date [Sun May 18 15:46:20 CST 2014]; root of context hierarchy
2014-5-18 15:46:20 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springBeanTest/beans.xml]
【BeanFactoryPostProcessor接口】实现类实例化!
【BeanFactoryPostProcessor接口】调用postProcessBeanFactory方法
【BeanPostProcessor接口】实现类实例化!
【InstantiationAwareBeanPostProcessorAdapter】子类实例化!
2014-5-18 15:46:20 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@9934d4: defining beans [beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor,person]; root of factory hierarchy
【InstantiationAwareBeanPostProcessor接口】调用postProcessBeforeInstantiation方法
【构造器】调用bean Person 的构造器实例化
【InstantiationAwareBeanPostProcessor接口】调用postProcessPropertyValues方法
【注入属性】注入属性address (注入XML中配置bean的属性,Spring通过反射调用bean的setter())
【注入属性】注入属性name
【注入属性】注入属性phone
【BeanNameAware接口】调用BeanNameAware.setBeanName()
【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()
【BeanPostProcessor接口】方法postProcessBeforeInitialization对属性进行更改!
【InitializingBean接口】调用InitializingBean.afterPropertiesSet()
【init-method】调用<bean>的init-method属性指定的初始化方法
【BeanPostProcessor接口】方法postProcessAfterInitialization对属性进行更改!
【InstantiationAwareBeanPostProcessor接口】调用postProcessAfterInitialization方法
容器初始化成功
Person [address=广州, name=张三, phone=110]
现在开始关闭容器!
【DiposibleBean接口】调用DiposibleBean.destory()
【destroy-method】调用<bean>的destroy-method属性指定的初始化方法
容器级BeanFactoryPostProcessor接口Bean(1个方法)
BeanFactory后处理器,其作用是在BeanFactory容器构建好后,执行postProcessBeanFactory得到BeanFactory对象。通过BeanFactory对象可以得到容器各个Bean的BeanDefinition(Bean的配置信息对象)。
@Component
public class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor {
private static Log log = LogFactory.getLog(BeanFactoryPostProcessorImpl.class);
public BeanFactoryPostProcessorImpl() {
super();
log.info("bean工厂后处理器实例化");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
log.info("取得BeanFactory容器");
log.info("通过BeanFactory容器 ,取得 bean-id==test 的 BeanDefinition ");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("test");
log.info("修改beanDefinition属性值");
beanDefinition.getPropertyValues().addPropertyValue("address", "110");//address是test的属性
}
}
容器级InstantiationAwareBeanPostProcessor接口Bean(3个方法)
https://www.jianshu.com/p/cee031ddae72
Bean实例化后处理器,其继承BeanPostProcessor接口
监控整个容器中各个Bean对象的实例化前后和初始化后。一般我们继承Spring为其提供的适配器类InstantiationAwareBeanPostProcessorAdapter来使用它。
方法postProcessPropertyValues用来操作属性,在bean实例化后执行,返回值也应该是PropertyValues对象。@Autowire就是AutowiredAnnotationBeanPostProcessor此方法注入。
public class MyInstantiationAwareBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter {
public MyInstantiationAwareBeanPostProcessor() {
super();
System.out.println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
}
// 接口方法、实例化Bean之前调用
@Override
public Object postProcessBeforeInstantiation(Class beanClass,
String beanName) throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
return null;
}
// 接口方法、实例化后执行
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
//@AutoWired依赖注入在此处实现
System.out.println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
return pvs;
}
// 接口方法、初始化Bean之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
return bean;
}
}
容器级BeanPostProcessor接口Bean(2个方法)
Bean后处理器,监控整个容器中各个Bean对象的实例化之后在初始化前后,容器中要执行或已完成初始化的Bean实例都会被Spring传递到BeanPostProcessor处理器中。可以在此处修改Bean的属性或为Bean生成包装/代理对象。
AOP就是在postProcessAfterInitialization中生成代理对象,替换原容器的Bean。
@Component
public class BeanPostProcessorImpl implements BeanPostProcessor {
private static Log log = LogFactory.getLog(BeanPostProcessorImpl.class);
public BeanPostProcessorImpl(){
super();
log.info("这是BeanPostProcessorImpl实现类的实例化,bean后处理器");
}
@Nullable
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
log.info("对初始化之前的Bean进行处理,beanName:"+beanName);
//容器中每一个Bean对象初始化前,都会传递进入此方法
//拿到bean的对象引用可以直接修改其属性
Student stu = null;
if("student".equals(beanname) || bean instanceof Student) {
stu = (Student) bean;
stu.setName("Jack");
}
//若只是修改bean的属性则,即使return null也生效。因为直接对bean的引用对象进行修改
return bean;
}
@Nullable
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("对初始化之后的Bean进行处理,beanName:"+beanName);
//容器中每一个Bean对象初始化后,都会传递进入此方法
if("student".equals(beanname) || bean instanceof Student) {
//生成bean的包装类/代理类对象后,必须把其新引用返回才能替换容器中的Bean
//注意:1 必须把其新引用返回才生效; 2 此时Bean的类型变为StudentProxy
return new StudentProxy(bean);
}
return bean;
}
}
源码中执行逻辑
传入当前bean引用existingBean,遍历BeanPostProcessor.postProcessBeforeInitialization若返回值不为null则替换Bean引用继续执行,若为null则终止遍历返回result。返回的result会替换Bean引用。
//bean初始化执行BeanPostProcessor
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
//postProcessAfterInitialization同理
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
//立即返回当前引用
return result;
}
//bean引用被替换
result = current;
}
return result;
}
简单用例:
下面的代码我们做的一个事情就是:数据库配置文件我们经常写的是用户名和密码,但是这样并不安全,所以我们在配置文件中使用加密带加盐的密码
利用下面的类进行解密,当然目前开源的项目中有这样的一个组件技术:jasypt-spring-boot-starter大家可以去了解一下
@Component
@Slf4j
public class PwdDecodeExtension implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
/**
* 注意这里我们对bean做了修改之后要把这个bean返回回去,这样的话我们修改的bean才会被重新的添加到ioc
* 的容器当中,我们做的修改才会生效
*/
System.err.println(beanName);
if (bean instanceof DruidDataSource){
DruidDataSource dataSource = (DruidDataSource) bean;
String password = dataSource.getPassword();
// 在这里我们可以对这个密码进行一系列的操作,这个怎么去做,相信你自有办法
log.info("数据库的密码=====>{}",password);
}
return bean;
}
}
在BeanFactory后处理器执行postProcessBeanFactory方法后,Spring开始实例化BeanPostProcessor。若查看ClassPathXmlApplicationContext的源码会发现其refresh方法。
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
//创建BeanFactory容器,解析XML封装到BeanDefinition,此时Bean不实例化
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
//BeanFactoryPostProcessor执行postProcessBeanFactory()
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册BeanPostProcessors,监控Bean初始化
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
普通Bean生命周期
一个bean的生命周期可以简述为以下几步
- 实例化前,Spring容器会先实例化其需要依赖注入的,但是不再缓存中的Bean
- 实例化bean对象(通过构造方法或者工厂方法)。
- 设置bean对象属性(setter()等 包含:配置的属性+@AutoWired)
- 检查Aware接口(BeanNameAware、BeanFactoryAware、ApplicationContextAware)
- 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
- 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory(BeanFactory beanFactory)方法,传入工厂自身
- 如果Bean实现了ApplicationContextAware接口,工厂调用setApplicationContext(ApplicationContext applicationContext)方法传入Spring应用上下文
- 将Bean实例传递给BeanPostProcessor处理器(实现了此容器级接口的Bean)的postProcessBeforeInitialization(Object bean, String beanname)方法
- 初始化Bean对象 调用的初始化方法 afterPropertiesSet+init-method (@RequestMapping注册在此完成https://blog.csdn.net/shanchahua123456/article/details/89816167)
- 将Bean实例传递给BeanPostProcessor处理器(实现了此容器级接口的Bean))的postProcessAfterInitialization(Object bean, String beanname)方法
- 使用Bean
- 容器关闭之前,调用Bean的销毁方法