Spring中的后置处理器BeanPostProcessor讲解

- 日理万妓 2021-11-08 21:38 415阅读 0赞

BeanPostProcessor接口作用:

如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

  1. package com.test.spring;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. /**
  5. * bean后置处理器
  6. * @author zss
  7. *
  8. */
  9. public class PostProcessor implements BeanPostProcessor {
  10. @Override
  11. public Object postProcessBeforeInitialization(Object bean,
  12. String beanName) throws BeansException {
  13. if ("narCodeService".equals(beanName)) {//过滤掉bean实例ID为narCodeService
  14. return bean;
  15. }
  16. System.out.println("后置处理器处理bean=【"+beanName+"】开始");
  17. try {
  18. Thread.sleep(1000);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. return bean;
  23. }
  24. @Override
  25. public Object postProcessAfterInitialization(Object bean,
  26. String beanName) throws BeansException {
  27. if ("narCodeService".equals(beanName)) {
  28. return bean;
  29. }
  30. System.out.println("后置处理器处理bean=【"+beanName+"】完毕!");
  31. try {
  32. Thread.sleep(1000);
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. return bean;
  37. }
  38. }

注意:接口中两个方法不能返回null,如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象,因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中!

将Spring的后置处理器PostProcessor配置到Spring配置文件中

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- 定义一个bean -->
  7. <bean id="narCodeService" class="com.test.service.impl.NarCodeServiceImpl">
  8. </bean>
  9. <bean id="beanLifecycle" class="com.test.spring.BeanLifecycle" init-method="init" destroy-method="close">
  10. <property name="name" value="张三"></property>
  11. <property name="sex" value="男"></property>
  12. </bean>
  13. <!-- Spring后置处理器 -->
  14. <bean id="postProcessor" class="com.test.spring.PostProcessor"/>
  15. </beans>

BeanPostProcessor API:

  1. public interface BeanPostProcessor {
  2. //实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
  3. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  4. //实例化、依赖注入、初始化完毕时执行
  5. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  6. }

由API可以看出:
1:后置处理器的postProcessorBeforeInitailization方法是在bean实例化,依赖注入之后及自定义初始化方法(例如:配置文件中bean标签添加init-method属性指定Java类中初始化方法、
@PostConstruct注解指定初始化方法,Java类实现InitailztingBean接口)之前调用
2:后置处理器的postProcessorAfterInitailization方法是在bean实例化、依赖注入及自定义初始化方法之后调用

注意:
1.BeanFactory和ApplicationContext两个容器对待bean的后置处理器稍微有些不同。ApplicationContext容器会自动检测Spring配置文件中那些bean所对应的Java类实现了BeanPostProcessor
接口,并自动把它们注册为后置处理器。在创建bean过程中调用它们,所以部署一个后置处理器跟普通的bean没有什么太大区别。
2.BeanFactory容器注册bean后置处理器时必须通过代码显示的注册,在IoC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法

  1. void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

Spring如何调用多个BeanPostProcessor实现类:

我们可以在Spring配置文件中添加多个BeanPostProcessor(后置处理器)接口实现类,在默认情况下Spring容器会根据后置处理器的定义顺序来依次调用。

在此我向大家推荐一个架构学习交流群。交流学习群号:点击即可加入 里面资深架构师会分享一些整理好的录制视频录像和BATJ面试题:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多。

Spring配置文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- bean定义 -->
  7. <bean id="narCodeService" class="com.test.service.impl.NarCodeServiceImpl">
  8. </bean>
  9. <bean id="postProcessor" class="com.test.spring.PostProcessor"/>
  10. <bean id="postProcessorB" class="com.test.spring.PostProcessorB"/>
  11. </beans>

BeanPostProcessor实现类:

  1. package com.test.spring;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. /**
  5. * bean后置处理器
  6. * @author zss
  7. *
  8. */
  9. public class PostProcessor implements BeanPostProcessor {
  10. @Override
  11. public Object postProcessBeforeInitialization(Object bean,
  12. String beanName) throws BeansException {
  13. System.out.println("后置处理器处理bean=【"+beanName+"】开始");
  14. try {
  15. Thread.sleep(1000);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. return bean;
  20. }
  21. @Override
  22. public Object postProcessAfterInitialization(Object bean,
  23. String beanName) throws BeansException {
  24. System.out.println("后置处理器处理bean=【"+beanName+"】完毕!");
  25. try {
  26. Thread.sleep(1000);
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. return bean;
  31. }
  32. }
  33. ----------------------------------------------------------------------------------------------------------------------------------------
  34. package com.test.spring;
  35. import org.springframework.beans.BeansException;
  36. import org.springframework.beans.factory.config.BeanPostProcessor;
  37. public class PostProcessorB implements BeanPostProcessor {
  38. @Override
  39. public Object postProcessBeforeInitialization(Object bean,
  40. String beanName) throws BeansException {
  41. System.out.println("后置处理器开始调用了");
  42. try {
  43. Thread.sleep(1000);
  44. } catch (InterruptedException e) {
  45. e.printStackTrace();
  46. }
  47. return bean;
  48. }
  49. @Override
  50. public Object postProcessAfterInitialization(Object bean,
  51. String beanName) throws BeansException {
  52. System.out.println("后置处理器调用结束了");
  53. try {
  54. Thread.sleep(1000);
  55. } catch (InterruptedException e) {
  56. e.printStackTrace();
  57. }
  58. return bean;
  59. }
  60. }
  61. Test case:
  62. package com.test.spring;
  63. import org.junit.Before;
  64. import org.junit.Test;
  65. import org.springframework.context.support.AbstractApplicationContext;
  66. import org.springframework.context.support.ClassPathXmlApplicationContext;
  67. public class T {
  68. AbstractApplicationContext applicationcontext=null;
  69. @Before
  70. public void before() {
  71. System.out.println("》》》Spring ApplicationContext容器开始初始化了......");
  72. applicationcontext= new ClassPathXmlApplicationContext(new String[]{"test1-service.xml"});
  73. System.out.println("》》》Spring ApplicationContext容器初始化完毕了......");
  74. }
  75. @Test
  76. public void test() {
  77. applicationcontext.registerShutdownHook();
  78. }
  79. }

测试结果:

》》》Spring ApplicationContext容器开始初始化了…
2017-03-19 10:50:29 INFO:ClassPathXmlApplicationContext-Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@18c92ff9: startup date [Sun Mar 19 10:50:29 CST 2017]; root of context hierarchy
2017-03-19 10:50:29 INFO:XmlBeanDefinitionReader-Loading XML bean definitions from class path resource [test1-service.xml]
后置处理器处理bean=【narCodeService】开始
后置处理器开始调用了
后置处理器处理bean=【narCodeService】完毕!
后置处理器调用结束了
》》》Spring ApplicationContext容器初始化完毕了…
2017-03-19 10:50:34 INFO:ClassPathXmlApplicationContext-Closing org.springframework.context.support.ClassPathXmlApplicationContext@18c92ff9: startup date [Sun Mar 19 10:50:29 CST 2017]; root of context hierarchy
在Spring机制中可以指定后置处理器调用顺序,通过让BeanPostProcessor接口实现类实现Ordered接getOrder方法,该方法返回一整数,默认值为 0,优先级最高,值越大优先级越低。

发表评论

表情:
评论列表 (有 0 条评论,415人围观)

还没有评论,来说两句吧...

相关阅读