首页 > 其他分享 >【Spring】BeanPostProcessor后置处理器

【Spring】BeanPostProcessor后置处理器

时间:2023-10-12 11:22:54浏览次数:35  
标签:BeanPostProcessor 后置 Spring Object bean User postProcessBeforeInitialization 处理器

BeanPostProcessor后置处理器可以在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

标签:BeanPostProcessor,后置,Spring,Object,bean,User,postProcessBeforeInitialization,处理器
From: https://www.cnblogs.com/shanml/p/17759087.html

相关文章

  • Spring MVC 与 Spring Webflux 性能测试,谁更强?
    如果你已经使用Spring一段时间或者是编程初学者,你一定听说过使用响应式编程比传统的线程池风格更好。自Spring诞生以来,开发者创建Java企业应用程序就变得更加容易。它提供了在企业环境中使用Java语言所需的一切,支持Groovy和Kotlin作为JVM上的替代语言,并且可以根据......
  • Spring Cloud 2023 新特性 同步网关
    网关不支持传统Servlet容器SpringCloudGateway需要运行在提供的Netty运行时。它不能在传统的Servlet容器中工作,也不能在构建为WAR时工作。WebFlux使用了异步非阻塞的编程模型,相较于传统的MVCServlet需要理解和适应新的编程范式和响应式编程概念,因此学习曲线可能......
  • Spring Boot 日期格式化
    我们先了解下,为什么需要配置日期格式化?通常情况下,发起一个Http请求,SpringBoot会根据请求路径映射到指定Controller上的某个方法的参数上,接着,Spring会自动进行类型转换。对于日期类型的参数,Spring默认是没有配置如何将字符串转换成日期类型的未配置日期格式化会如何?我......
  • spring-mvc 请求流程学习
    参考:01、基础入门-SpringBoot2课程介绍_哔哩哔哩_bilibili请求进入HttpServlet的doGet方法然后通过实现类org.springframework.web.servlet.FrameworkServlet#doGet()调用org.springframework.web.servlet.FrameworkServlet#processRequest----》org.springframework.web.ser......
  • SpringBean生命周期
    SpringBean生命周期读源码小方法:先把所有代码块折叠,看整体,再逐步进入局部,忽略异常处理。写简单程序打断点调试。本文主要ref结论生命周期主要的扩展点:实例化(doGetBean()->createBeanInstance()),注入(populate),初始化(initializeBean),销毁。一般processor都是在这些点前后......
  • springboot跨域解决方案
    @BeanpublicCorsFiltercorsFilter(){CorsConfigurationconfig=newCorsConfiguration();config.addAllowedOriginPattern("*");config.setAllowCredentials(true);config.addAllowedMethod("OPTIONS");......
  • 7min到40s:SpringBoot 启动优化实践!
    0背景公司SpringBoot项目在日常开发过程中发现服务启动过程异常缓慢,常常需要6-7分钟才能暴露端口,严重降低开发效率。通过SpringBoot的SpringApplicationRunListener、BeanPostProcessor原理和源码调试等手段排查发现,在Bean扫描和Bean注入这个两个阶段有很大的性能......
  • springMVC @Test方法中如何请求https
    原文链接:https://www.longkui.site/error/springmvc-test-https/4823/0.背景springMVC环境,需要在@Test方法中发送一个https请求,按照格式要求发送了,结果报错org.springframework.web.client.ResourceAccessException:I/OerroronPOSTrequestfor"https://xxxx/xxx/xx:jav......
  • SpringBoot实现CORS跨域的三种方式
    一、实现WebMvcConfigurer接口@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{/***添加跨域支持*/@OverridepublicvoidaddCorsMappings(CorsRegistryregistry){//允许跨域访问的路径'/**'表示应用的所有方法......
  • spring扫描本项目包下类数量 方法数量
    importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.core.io.Resource;importorg.springframework.core.io.support.PathMatc......