【Spring】BeanPostProcessor后置处理器

金歌  金牌会员 | 2023-10-27 19:50:37 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 937|帖子 937|积分 2811

BeanPostProcessor后置处理器可以在Bean初始化前后做一些事情,注意这里是bean的初始化,不是实例化,BeanPostProcessor是一个接口,里面提供了两个方法,分别为postProcessBeforeInitialization(初始化之前)和postProcessAfterInitialization(初始化之后),在方法入参中有两个参数,一个bean对象,一个bean名称,这里也可以看出,在初始化之前应该已经完成了bean的实例化,这里把实例化的bean对象作为参数传了进来:
  1. public interface BeanPostProcessor {
  2.     @Nullable
  3.     default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  4.         return bean;
  5.     }
  6.     @Nullable
  7.     default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  8.         return bean;
  9.     }
  10. }
复制代码
来看一个例子,首先创建一个Bean,使用@Component将该bean交给Spring容器管理:
  1. // 使用@Component将该bean交给Spring管理
  2. @Component
  3. public class User {
  4.     private String name;
  5.     public User() {
  6.         System.out.println("调用User构造函数");
  7.     }
  8.     public String getName() {
  9.         return name;
  10.     }
  11.     public void setName(String name) {
  12.         this.name = name;
  13.     }
  14. }
复制代码
接下来创建一个自定义的Bean后置处理器,实现BeanPostProcessor接口,并实现postProcessBeforeInitialization和postProcessAfterInitialization方法,使用@Component将该bean交给Spring管理,Spring会获取后置处理器,在bean进行初始化前后触发对应的方法。
为了打印便于观察输出结果,这里对Bean类型进行了判断,只有User类型才打印日志:
  1. // 使用@Component将该bean交给Spring管理
  2. @Component
  3. public class MyBeanPostProcessor implements BeanPostProcessor {
  4.     @Override
  5.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  6.         // 只处理User类型
  7.         if (bean instanceof User) {
  8.             System.out.println("【后置处理器】postProcessBeforeInitialization");
  9.         }
  10.         return bean;
  11.     }
  12.     @Override
  13.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  14.         // 只处理User类型
  15.         if (bean instanceof User) {
  16.             System.out.println("【后置处理器】postProcessBeforeInitialization");
  17.         }
  18.         return bean;
  19.     }
  20. }
复制代码
进行测试,从容器中获取user对象:
  1. // 注意这里要扫描包
  2. @ComponentScan(basePackages = {"com.example.demo"})
  3. @SpringBootTest
  4. class SpringbootWebApplicationTests {
  5.         @Test
  6.         void contextLoads() {
  7.         AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class);
  8.                 User User = (User) applicationContext.getBean("user", User.class);
  9.                 System.out.println("userName:" + User.getName());
  10.         }
  11. }
复制代码
打印结果:
  1. 调用User构造函数
  2. 【后置处理器】postProcessBeforeInitialization
  3. 【后置处理器】postProcessBeforeInitialization
  4. userName:null
复制代码
从结果中也可以看出,后置处理器中的方法,是在bean已经完成了实例化之后触发的,所以通过后置处理器可以对bean的属性进行设置,甚至可以更改bean对象本身。
比如在postProcessBeforeInitialization方法中,为User设置名称:
  1. // 使用@Component将该bean交给Spring管理
  2. @Component
  3. public class MyBeanPostProcessor implements BeanPostProcessor {
  4.     @Override
  5.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  6.         // 只处理User类型
  7.         if (bean instanceof User) {
  8.             User user = (User) bean;
  9.             user.setName("zhangsm");
  10.             System.out.println("【后置处理器】postProcessBeforeInitialization");
  11.             return user;
  12.         }
  13.         return bean;
  14.     }
  15. }
复制代码
再次运行将会输出以下内容:
  1. 调用User构造函数
  2. 【后置处理器】postProcessBeforeInitialization
  3. 【后置处理器】postProcessBeforeInitialization
  4. userName:zhangsm
复制代码
再看一下对bean本身进行更改的例子,再新增一个AdminUser类,继承User,注意AdminUser没有使用注解,也就是没有交给Spring进行管理,之后我们通过手动实例化的方式,将Spring容器中User改成AdminUser类型:
  1. public class AdminUser extends User {
  2. }
复制代码
修改MyBeanPostProcessor中的postProcessAfterInitialization方法,方法的返回值是Object类型,在这里更改bean对象并返回进行替换:
  1. @Component
  2. public class MyBeanPostProcessor implements BeanPostProcessor {
  3.     @Override
  4.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  5.         if (bean instanceof User) {
  6.             // 这里手动创建了一个AdminUser并返回
  7.             AdminUser user = new AdminUser();
  8.             user.setName("administator");
  9.             System.out.println("【后置处理器】postProcessBeforeInitialization");
  10.             return user;
  11.         }
  12.         return bean;
  13.     }
  14. }
复制代码
修改测试类,这次把class信息也打印:
  1. @ComponentScan(basePackages = {"com.example.demo"})
  2. @SpringBootTest
  3. class SpringbootWebApplicationTests {
  4.         @Test
  5.         void contextLoads() {
  6.                 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class);
  7.                 User User = (User) applicationContext.getBean("user", User.class);
  8.                 System.out.println("userClass:" + User.getClass());
  9.                 System.out.println("userName:" + User.getName());
  10.         }
  11. }
复制代码
运行结果,可以看到拿到的bean已经是更改后的AdminUser
  1. 调用User构造函数          // 这里是User实例化时输出的
  2. 【后置处理器】postProcessBeforeInitialization
  3. 调用User构造函数         // 这里是AdminUser实例化时输出的
  4. 【后置处理器】postProcessBeforeInitialization
  5. userClass:class com.example.demo.model.AdminUser
  6. userName:administator
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表