文章目录
一句话:bean后置处理器就是对bean的生命周期的各阶段的增强
1、bean生命周期
启动类:
@SpringBootApplication
public class A03 {
public static void main(String[] args) {
//创建容器
ConfigurableApplicationContext context =
SpringApplication.run(A03.class, args);
//关闭容器
context.close();
}
}
添加扫描bean
@Component
@Slf4j
public class LifeCycleBean {
public LifeCycleBean() {
log.debug("bean生命周期>>>>>>>>>>>>>>>>>>>构造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home) {
log.debug("bean生命周期>>>>>>>>>>>>>>>>>>依赖注入: {}", home);
}
@PostConstruct
public void init() {
log.debug("bean生命周期>>>>>>>>>>>>>>>>>>>初始化");
}
@PreDestroy
public void destroy() {
log.debug("bean生命周期>>>>>>>>>>>>>>>>>>>销毁");
}
}
输出结果:
[INFO ] 18:03:31.555 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
[INFO ] 18:03:31.563 [main] o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
[INFO ] 18:03:31.564 [main] o.a.catalina.core.StandardService - Starting service [Tomcat]
[INFO ] 18:03:31.564 [main] o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.53]
[INFO ] 18:03:31.662 [main] o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
[INFO ] 18:03:31.663 [main] o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 994 ms
[DEBUG] 18:03:31.710 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>>构造
[DEBUG] 18:03:31.713 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>依赖注入: E:\java\jdk\jdk8\tools
[DEBUG] 18:03:31.714 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>>初始化
[INFO ] 18:03:31.917 [main] o.s.b.a.w.s.WelcomePageHandlerMapping - Adding welcome page: class path resource [static/index.html]
[INFO ] 18:03:31.986 [main] c.a.d.s.b.a.DruidDataSourceAutoConfigure - Init DruidDataSource
[INFO ] 18:03:32.055 [main] c.a.druid.pool.DruidDataSource - {dataSource-1} inited
[INFO ] 18:03:32.416 [main] o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
[INFO ] 18:03:32.429 [main] o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
[INFO ] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
[TRACE] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Detected org.springframework.web.multipart.support.StandardServletMultipartResolver@4eed2acf
[TRACE] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Detected org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@36fc05ff
[TRACE] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Detected org.springframework.web.servlet.theme.FixedThemeResolver@57c47a9e
[TRACE] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Detected DefaultRequestToViewNameTranslator
[TRACE] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Detected SessionFlashMapManager
[DEBUG] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
[INFO ] 18:03:32.430 [main] o.s.web.servlet.DispatcherServlet - Completed initialization in 0 ms
[INFO ] 18:03:32.432 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
[INFO ] 18:03:32.441 [main] com.xc.a03.A03 - Started A03 in 2.152 seconds (JVM running for 3.009)
[INFO ] 18:03:32.713 [main] c.a.druid.pool.DruidDataSource - {dataSource-1} closing ...
[INFO ] 18:03:32.714 [main] c.a.druid.pool.DruidDataSource - {dataSource-1} closed
[DEBUG] 18:03:32.715 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>>销毁
Process finished with exit code 0
2、常用的bean后置处理器接口
2.1、初始化-Bean后置处理器
- BeanPostProcessor是bean后置处理器最底层接口
- 两个方法返回的bean会替换原来的bean
- 初始化阶段在实例化和属性填充之后
- 初始化之前执行:解析注解@PostConstruct、@ConfigurationProperties
- 初始化之后执行:代理增强
public interface BeanPostProcessor {
//bean初始化前执行
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//bean初始化后执行
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
- 自定义初始化后置处理器
@Component
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("初始化后置处理器>>>>>>> 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("初始化后置处理器>>>>>>> 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
return bean;
}
}
2.2、实例化-Bean后置处理器
- BeanPostProcessor的扩展接口(子接口)
- 实例化之前执行:返回的bean对象可能是要使用的代理,而不是目标bean,从而有效地抑制了目标bean的默认实例化。如果此方法返回非null对象,则bean创建过程将被短路(也就是正常bean实例化的后续流程不再执行)
- 实例化之后执行:返回结果为true时,说明应该为bean设置属性。如果返回结果为false,跳过bean属性赋值环节
- 依赖注入阶段执行:解析注解@Autowired、@Value、@Resource
- postProcessPropertyValues:这个方法在spring低版本中使用,在高版本已经过时了,使用postProcessProperties代替
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
//bean实例化前执行
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
//bean实例化后执行
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
//依赖注入阶段执行
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
return null;
}
/** @deprecated */
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
- 自定义实例化后置处理器
@Component
@Slf4j
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("实例化后置处理器>>>>>>> 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
log.debug("实例化后置处理器>>>>>>>实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("实例化后置处理器>>>>>>> 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
return pvs;
}
}
2.3、销毁-Bean后置处理器
- BeanPostProcessor的扩展接口(子接口)
- 销毁之前执行:解析注解@PreDestroy
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
//这里实现销毁对象的逻辑
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
//判断是否需要处理这个对象的销毁
default boolean requiresDestruction(Object bean) {
return true;
}
}
- 自定义销毁后置处理器
@Component
@Slf4j
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("销毁后置处理器>>>>>>> 销毁之前执行, 如 @PreDestroy");
}
}
生命周期bean添加后置处理器后输出结果:
[INFO ] 18:07:14.639 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
[INFO ] 18:07:14.646 [main] o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
[INFO ] 18:07:14.646 [main] o.a.catalina.core.StandardService - Starting service [Tomcat]
[INFO ] 18:07:14.646 [main] o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.53]
[INFO ] 18:07:14.715 [main] o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
[INFO ] 18:07:14.715 [main] o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 867 ms
[DEBUG] 18:07:14.748 [main] c.x.a.MyInstantiationAwareBeanPostProcessor - 实例化后置处理器>>>>>>> 实例化之前执行, 这里返回的对象会替换掉原本的 bean
[DEBUG] 18:07:14.749 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>>构造
[DEBUG] 18:07:14.750 [main] c.x.a.MyInstantiationAwareBeanPostProcessor - 实例化后置处理器>>>>>>>实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段
[DEBUG] 18:07:14.750 [main] c.x.a.MyInstantiationAwareBeanPostProcessor - 实例化后置处理器>>>>>>> 依赖注入阶段执行, 如 @Autowired、@Value、@Resource
[DEBUG] 18:07:14.751 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>依赖注入: E:\java\jdk\jdk8\tools
[DEBUG] 18:07:14.752 [main] com.xc.a03.MyBeanPostProcessor - 初始化后置处理器>>>>>>> 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties
[DEBUG] 18:07:14.752 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>>初始化
[DEBUG] 18:07:14.752 [main] com.xc.a03.MyBeanPostProcessor - 初始化后置处理器>>>>>>> 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强
[INFO ] 18:07:14.920 [main] o.s.b.a.w.s.WelcomePageHandlerMapping - Adding welcome page: class path resource [static/index.html]
[INFO ] 18:07:14.986 [main] c.a.d.s.b.a.DruidDataSourceAutoConfigure - Init DruidDataSource
[INFO ] 18:07:15.056 [main] c.a.druid.pool.DruidDataSource - {dataSource-1} inited
[INFO ] 18:07:15.273 [main] o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
[INFO ] 18:07:15.285 [main] o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
[INFO ] 18:07:15.285 [main] o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
[TRACE] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - Detected org.springframework.web.multipart.support.StandardServletMultipartResolver@57c47a9e
[TRACE] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - Detected org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@642505c7
[TRACE] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - Detected org.springframework.web.servlet.theme.FixedThemeResolver@4339e0de
[TRACE] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - Detected DefaultRequestToViewNameTranslator
[TRACE] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - Detected SessionFlashMapManager
[DEBUG] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
[INFO ] 18:07:15.286 [main] o.s.web.servlet.DispatcherServlet - Completed initialization in 0 ms
[INFO ] 18:07:15.287 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
[INFO ] 18:07:15.295 [main] com.xc.a03.A03 - Started A03 in 1.781 seconds (JVM running for 2.529)
[INFO ] 18:07:15.581 [main] c.a.druid.pool.DruidDataSource - {dataSource-1} closing ...
[INFO ] 18:07:15.582 [main] c.a.druid.pool.DruidDataSource - {dataSource-1} closed
[DEBUG] 18:07:15.584 [main] c.x.a.MyDestructionAwareBeanPostProcessor - 销毁后置处理器>>>>>>> 销毁之前执行, 如 @PreDestroy
[DEBUG] 18:07:15.584 [main] com.xc.a03.LifeCycleBean - bean生命周期>>>>>>>>>>>>>>>>>>>销毁
Process finished with exit code 0
3、模板方法设计模式,扩展bean后置处理器
- getBean方法执行流程步骤已确定
- 后置处理器接口集合遍历,添加后置处理器只需要bean工厂添加到后置处理器集合汇总即可
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
}
// 模板方法
class MyBeanFactory {
private final List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor processor) {
processors.add(processor);
}
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean); // @Autowired, @Resource
for (BeanPostProcessor processor : processors) {
processor.inject(bean);
}
System.out.println("初始化 " + bean);
return bean;
}
}
interface BeanPostProcessor {
public void inject(Object bean); // 对依赖注入阶段的扩展
}
输出结果:
构造 java.lang.Object@533ddba
依赖注入 java.lang.Object@533ddba
解析 @Autowired
解析 @Resource
初始化 java.lang.Object@533ddba
Process finished with exit code 0
4、bean后置处理器排序
- 实现了 PriorityOrdered 接口的优先级最高
- 实现了 Ordered 接口与加了 @Order 注解的平级, 按数字升序
- 其它的排在最后
public class TestProcessOrder {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//排序
List<BeanPostProcessor> list = Arrays.asList(new P1(), new P2(), new P3(), new P4(), new P5());
list.sort(beanFactory.getDependencyComparator());
//遍历执行后置处理器的初始化之前方法
list.forEach(processor->{
processor.postProcessBeforeInitialization(new Object(), "");
});
}
}
@Order(1)
class P1 implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization @Order(1)");
return bean;
}
}
@Order(2)
class P2 implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization @Order(2)");
return bean;
}
}
class P3 implements BeanPostProcessor, PriorityOrdered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization PriorityOrdered getOrder() == 100");
return bean;
}
@Override
public int getOrder() {
return 100;
}
}
class P4 implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization Ordered getOrder() == 0");
return bean;
}
@Override
public int getOrder() {
return 0;
}
}
class P5 implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization 无排序接口");
return bean;
}
}
输出结果:
Connected to the target VM, address: '127.0.0.1:63224', transport: 'socket'
postProcessBeforeInitialization PriorityOrdered getOrder() == 100
postProcessBeforeInitialization Ordered getOrder() == 0
postProcessBeforeInitialization @Order(1)
postProcessBeforeInitialization @Order(2)
postProcessBeforeInitialization 无排序接口
Disconnected from the target VM, address: '127.0.0.1:63224', transport: 'socket'
Process finished with exit code 0
5、bean后置处理器实现类的作用
准备bean:
@Slf4j
public class Bean1 {
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("@Autowired 生效: {}", bean2);
this.bean2 = bean2;
}
@Autowired
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.debug("@Resource 生效: {}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value 生效: {}", home);
this.home = home;
}
@PostConstruct
public void init() {
log.debug("@PostConstruct 生效");
}
@PreDestroy
public void destroy() {
log.debug("@PreDestroy 生效");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", home='" + home + '\'' +
'}';
}
}
public class Bean2 {
}
public class Bean3 {
}
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private String home;
private String version;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Bean4{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
启动类:
public class A04 {
public static void main(String[] args) {
// GenericApplicationContext 是一个【干净】的容器
GenericApplicationContext context = new GenericApplicationContext();
// 用原始方法注册三个 bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
// 解析表达式
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// @Autowired @Value
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// @Resource @PostConstruct @PreDestroy
context.registerBean(CommonAnnotationBeanPostProcessor.class);
//解析配置文件properties对象
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
// 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
context.refresh();
System.out.println(context.getBean(Bean1.class));
// 销毁容器
context.close();
}
}
输出结果:
[DEBUG] 22:37:41.613 [main] com.xc.a04.Bean1 - @Resource 生效: com.xc.a04.Bean3@f2f2cc1
[DEBUG] 22:37:41.661 [main] com.xc.a04.Bean1 - @Value 生效: E:\java\jdk\jdk8\tools
[DEBUG] 22:37:41.664 [main] com.xc.a04.Bean1 - @Autowired 生效: com.xc.a04.Bean2@2fd6b6c7
[DEBUG] 22:37:41.664 [main] com.xc.a04.Bean1 - @PostConstruct 生效
Bean1{bean2=com.xc.a04.Bean2@2fd6b6c7, bean3=com.xc.a04.Bean3@f2f2cc1, home='E:\java\jdk\jdk8\tools'}
[DEBUG] 22:37:41.905 [main] com.xc.a04.Bean1 - @PreDestroy 生效
Process finished with exit code 0
总结:后置处理器解析@Autowired@Resource@PostConstruct等一些列注解处理bean生命周期阶段(依赖注入, 初始化)的扩展功能
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148605.html