【Spring】BeanPostProcessor后置处理器

spring,beanpostprocessor,后置,处理器 · 浏览次数 : 28

小编点评

**BeanPostProcessor接口** `BeanPostProcessor` 接口是一个扩展点,可以在 Bean 初始化前后做一些事情。 **`postProcessBeforeInitialization` 方法** * 在 Bean 初始化之前执行的准备工作。 * 返回一个 `Object` 值,表示准备完毕后的对象。 **`postProcessAfterInitialization` 方法** * 在 Bean 初始化之后执行的处理工作。 * 返回一个 `Object` 值,表示处理完毕后的对象。 **使用 BeanPostProcessor** 1. 在 `@Component` 上标记要处理的 Bean 的类。 2. 创建一个实现 `BeanPostProcessor` 接口的类并实现 `postProcessBeforeInitialization` 和 `postProcessAfterInitialization` 方法。 3. 在 `@Bean` 方法中返回实现类。 **例子** ```java @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof User) { System.out.println("【后置处理器】postProcessBeforeInitialization"); return user; } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof User) { System.out.println("【后置处理器】postProcessAfterInitialization"); ((User) bean).setName("zhangsm"); return bean; } return bean; } } ``` **测试** ```java @Test public void contextLoads() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class); User user = (User) applicationContext.getBean("user", User.class); System.out.println("userName:\" + user.getName()); } ``` **输出** ``` 【后置处理器】postProcessBeforeInitialization 【后置处理器】postProcessBeforeInitializationuserName:zhangsm 【后置处理器】postProcessAfterInitialization ```

正文

BeanPostProcessor后置处理器是Spring提供的一个扩展点,可以在Bean初始化前后做一些事情,注意这里是bean的初始化,不是实例化,BeanPostProcessor是一个接口,里面提供了两个方法,分别为postProcessBeforeInitialization(初始化之前)和postProcessAfterInitialization(初始化之后),在方法入参中有两个参数,一个bean对象,一个bean名称,这里也可以看出,在初始化之前应该已经完成了bean的实例化,这里把实例化的bean对象作为参数传了进来:

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

来看一个例子,首先创建一个Bean,使用@Component将该bean交给Spring容器管理:

// 使用@Component将该bean交给Spring管理
@Component
public class User {

    private String name;

    public User() {
        System.out.println("调用User构造函数");
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

接下来创建一个自定义的Bean后置处理器,实现BeanPostProcessor接口,并实现postProcessBeforeInitialization和postProcessAfterInitialization方法,使用@Component将该bean交给Spring管理,Spring会获取后置处理器,在bean进行初始化前后触发对应的方法。

为了打印便于观察输出结果,这里对Bean类型进行了判断,只有User类型才打印日志:

// 使用@Component将该bean交给Spring管理
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 只处理User类型
        if (bean instanceof User) {
            System.out.println("【后置处理器】postProcessBeforeInitialization");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 只处理User类型
        if (bean instanceof User) {
            System.out.println("【后置处理器】postProcessBeforeInitialization");
        }
        return bean;
    }
}

进行测试,从容器中获取user对象:

// 注意这里要扫描包
@ComponentScan(basePackages = {"com.example.demo"})
@SpringBootTest
class SpringbootWebApplicationTests {

	@Test
	void contextLoads() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class);
		User User = (User) applicationContext.getBean("user", User.class);
		System.out.println("userName:" + User.getName());
	}

}

打印结果:

调用User构造函数
【后置处理器】postProcessBeforeInitialization
【后置处理器】postProcessBeforeInitialization
userName:null

从结果中也可以看出,后置处理器中的方法,是在bean已经完成了实例化之后触发的,所以通过后置处理器可以对bean的属性进行设置,甚至可以更改bean对象本身。

比如在postProcessBeforeInitialization方法中,为User设置名称:

// 使用@Component将该bean交给Spring管理
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 只处理User类型
        if (bean instanceof User) {
            User user = (User) bean;
            user.setName("zhangsm");
            System.out.println("【后置处理器】postProcessBeforeInitialization");
            return user;
        }
        return bean;
    }
}

再次运行将会输出以下内容:

调用User构造函数
【后置处理器】postProcessBeforeInitialization
【后置处理器】postProcessBeforeInitialization
userName:zhangsm

再看一下对bean本身进行更改的例子,再新增一个AdminUser类,继承User,注意AdminUser没有使用注解,也就是没有交给Spring进行管理,之后我们通过手动实例化的方式,将Spring容器中User改成AdminUser类型:

public class AdminUser extends User {
}

修改MyBeanPostProcessor中的postProcessAfterInitialization方法,方法的返回值是Object类型,在这里更改bean对象并返回进行替换:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof User) {
            // 这里手动创建了一个AdminUser并返回
            AdminUser user = new AdminUser();
            user.setName("administator");
            System.out.println("【后置处理器】postProcessBeforeInitialization");
            return user;
        }
        return bean;
    }
}

修改测试类,这次把class信息也打印:

@ComponentScan(basePackages = {"com.example.demo"})
@SpringBootTest
class SpringbootWebApplicationTests {

	@Test
	void contextLoads() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class);
		User User = (User) applicationContext.getBean("user", User.class);
		System.out.println("userClass:" + User.getClass());
		System.out.println("userName:" + User.getName());
	}

}

运行结果,可以看到拿到的bean已经是更改后的AdminUser

调用User构造函数          // 这里是User实例化时输出的
【后置处理器】postProcessBeforeInitialization
调用User构造函数         // 这里是AdminUser实例化时输出的
【后置处理器】postProcessBeforeInitialization
userClass:class com.example.demo.model.AdminUser
userName:administator

与【Spring】BeanPostProcessor后置处理器相似的内容:

【Spring】BeanPostProcessor后置处理器

BeanPostProcessor后置处理器是Spring提供的一个扩展点,可以在Bean初始化前后做一些事情,注意这里是bean的初始化,不是实例化,BeanPostProcessor是一个接口,里面提供了两个方法,分别为postProcessBeforeInitialization(初始化之前)

Spring源码:Bean生命周期(五)

在今天的文章中,我们将深入探讨 Bean 的属性注入和初始化流程,从而使其成为一个真正意义上的 Bean。这个过程包括属性注入、Aware 接口回调、BeanPostProcessor 的前置和后置处理等多个步骤,通过本文的学习,读者将能够更深入地了解 Spring 框架中 Bean 的属性注入和初始化过程,为后续的学习和实践打下坚实的基础。

Bean生命周期的扩展点:Bean Post Processor

摘要:在本篇文章中,我们将深入探讨Spring框架中的重要组件——BeanPostProcessor。首先,我们将了解其设计理念和目标,然后通过实际的例子学习如何基础使用它,如何通过BeanPostProcessor改变Bean的初始化结果以及如何利用它修改Bean的属性。 本文分享自华为云社区《S

Spring的三种依赖注入的方式

1、什么是依赖注入 依赖注入(Dependency Injection,简称DI),是IOC的一种别称,用来减少对象间的依赖关系。 提起依赖注入,就少不了IOC。 IOC(Inversion of Control,控制反转)是一种设计思想,它将原本在程序中手动创建对象的控制权,交由Spring框架来

使用 Spring 实现控制反转和依赖注入

使用 Spring 实现控制反转和依赖注入 概述 在本文中,我们将介绍IoC(控制反转)和DI(依赖注入)的概念,以及如何在Spring框架中实现它们。 什么是控制反转? 控制反转是软件工程中的一个原则,它将对象或程序的某些部分的控制权转移给容器或框架。我们最常在面向对象编程的上下文中使用它。 与传

Spring 对于事务上的应用的详细说明

1. Spring 对于事务上的应用的详细说明 @目录1. Spring 对于事务上的应用的详细说明每博一文案2. 事务概述3. 引入事务场景3.1 第一步:准备数据库表3.2 第二步:创建包结构3.3 第三步:准备对应数据库映射的 Bean 类3.4 第四步:编写持久层3.5 第五步:编写业务层3

谈谈 Spring 的过滤器和拦截器

我们在进行 Web 应用开发时,时常需要对请求进行拦截或处理,故 Spring 为我们提供了过滤器和拦截器来应对这种情况。那么两者之间有什么不同呢?本文将详细讲解两者的区别和对应的使用场景。

有意思!一个关于 Spring 历史的在线小游戏

发现 Spring One 的官网上有个好玩的彩蛋,分享给大家! 进到Spring One的官网,可以看到右下角有个类似马里奥游戏中的金币图标。 点击该金币之后,会打开一个新的页面,进入下面这样一个名为:The History Of Spring 的在线小游戏 你可以使用上下左右的方向键来控制Spr

手把手教你解决spring boot导入swagger2版本冲突问题,刘老师教编程

手把手教你解决spring boot导入swagger2版本冲突问题 本文仅为个人理解,欢迎大家批评指错 首先Spring Boot 3 和 Swagger 2 不兼容。在 Spring Boot 3 中,应该使用 Springdoc 或其他与 Spring Boot 3 兼容的 API 文档工具来

Spring MVC 中使用 RESTFul 编程风格

1. Spring MVC 中使用 RESTFul 编程风格 @目录1. Spring MVC 中使用 RESTFul 编程风格2. RESTFul 编程风格2.1 RESTFul 是什么2.2 RESTFul风格与传统方式对比3. Spring MVC 中使用 RESTFul 编程风格(增删改查)