1、简介
发
2、概念
2.1 基本介绍
2.1.1 BeanDefinitionRegistryPostProcessor 它是Spring框架的一个扩展点,用于对Bean定义的注册过程进行干预和定制。
2.1.2 BeanDefinitionRegistryPostProcessor 它继承BeanFactoryPostProcessor接口,并在其基础上扩展了一个新的方法,即:postProcessBeanDefinitionRegistry()方法。
2.2 用途
BeanDefinitionRegistryPostProcessor 在Spring容器初始化时,首先会读取应用程序中的配置文件,并解析出所有的Bean定义,然后将这些Bean定义注册到容器中。
在这个过程中,BeanDefinitionRegistryProcessor提供了一种机制,允许开发人员在Bean定义注册之前和之后对Bean定义进行自定义处理,例如添加,修改或删除Bean定义等。
2.3 具体原理
具体来说,BeanDefinitionRegistryPostProcessor提供了以下两个方法:
2.3.1 postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry):
该方法在所有Bean定义加载完成之后,Bean实例化之前被调用,允许开发人员对Bean定义进行自定义修改,例如添加,修改或删除Bean定义等。
2.3.2 postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory):
该方法是继承自BeanFactoryPostProcessor接口的方法,用于在BeanFactory完成实例化之后对BeanFactory进行后置处理。
那么我们通过BeanDefinitionRegistryPostProcessor接口,开发人员可以在Spring容器启动时干预Bean的注册过程,从而实现对Bean的自定义处理。
3、调用demo
3.1 案例一
3.1.1 Entity 类 (MyBean)
public class MyBean {
private String message = "Hello, World!";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
3.1.2 手写一个接口
这个接口实现BeanDefinitionRegistryPostProcessor和接口PriorityOrdered,在postProcessBeanDefinitionRegistry方法中对bean的操作进行增删查改
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
/**
* 重写BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 创建一个RootBeanDefinition实例,该实例对应的BeanClass是MyBean
RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
// 向BeanDefinitionRegistry注册MyBean的BeanDefinition
registry.registerBeanDefinition("myBean", beanDefinition);
// 查询和修改
BeanDefinition myBean = registry.getBeanDefinition("myBean");
System.out.println(myBean);
// 删除
registry.removeBeanDefinition("myBean");
}
/**
* 重写BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public int getOrder() {
return 1;
}
}
3.1.3 启动类
@SpringBootApplication
public class FactorybeanDemoApplication {
public static ConfigurableApplicationContext context ;
public static void main(String[] args) {
context = SpringApplication.run(FactorybeanDemoApplication.class, args);
MyBean bean = context.getBean(MyBean.class);
System.out.println("================"+bean.getMessage()+"===================");
}
}
- 上述代码会抛出No qualifying bean异常,因为我们把myBean的bd删除了
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.factorybean.factorybeandemo.factorybean.test.MyBean' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:343)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1101)
at com.factorybean.factorybeandemo.FactorybeanDemoApplication.main(FactorybeanDemoApplication.java:17)
... 5 more
- 注释掉“registry.removeBeanDefinition("myBean");” 就可以执行成功
2023-10-22 14:43:22.448 INFO 73304 --- [ restartedMain] c.f.f.FactorybeanDemoApplication : Started FactorybeanDemoApplication in 1.333 seconds (JVM running for 1.87)
================Hello, World!===================
3.2 案例二
3.2.1 配置类 (MyPostBeanRegistar)
@Configuration
public class MyPostBeanRegistar implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
System.out.println("postProcessBeanDefinitionRegistry is invoked");
String clzz= Base.class.getName();
for(int i=0;i<2;i++){
if(!beanDefinitionRegistry.containsBeanDefinition(i+""))
ResgistarUtils.registerBeanDefinations(i+"",clzz,beanDefinitionRegistry);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("postProcessBeanFactory is invoked");
}
}
3.2.2 注册Utils类 (ResgistarUtils)
public class ResgistarUtils {
/**
* 注册工具类方法
* @param className
* @param clzz
* @param beanDefinitionRegistry
*/
public static void registerBeanDefinations(String className, String clzz, BeanDefinitionRegistry beanDefinitionRegistry){
/**
* 通过 工厂方法来注入Bean
*/
BeanDefinitionBuilder builder= BeanDefinitionBuilder.genericBeanDefinition(MyfactoryBean.class);
builder.addPropertyValue("type",clzz);
builder.addPropertyValue("name",className);
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
if(className.equals("0")) {
beanDefinition.setPrimary(true);
}else{
//beanDefinition.s
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, beanDefinitionRegistry);
}
}
3.2.3 工厂bean接口实现
public class MyfactoryBean implements FactoryBean<Object> {
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Class<?> type;
private String name;
@Override
public Object getObject() throws Exception {
System.out.println("getObject");
if(this.name.equals("0")){
return new TestA();
}else if(this.name.equals("1")){
return new TestB();
}
throw new ClassNotFoundException("not found Base by name=["+name+"]");
}
@Override
public Class<?> getObjectType() {
return type;
}
}
3.2.4 Entity 类 (Base、TestA、TestB)
public interface Base {
void print();
}
public class TestA implements Base {
public TestA(){
System.out.println("TestA 够着");
}
@Override
public void print() {
System.out.println("testA aaa");
}
}
public class TestB implements Base {
public TestB(){
System.out.println("TestB 够着");
}
@Override
public void print() {
System.out.println("testB bbbb ");
}
}
3.2.5 测试 Controller 类 (TestController)
@RestController
public class TestController {
@Autowired
Base base1;
// @Autowired
// @Qualifier("1")
@Resource(name = "1")
Base base2;
@GetMapping("/testprint")
public String print(){
base1.print();
base2.print();
return "testprint";
}
}
3.2.6 启动类
@SpringBootApplication
public class FactorybeanDemoApplication {
public static ConfigurableApplicationContext context ;
public static void main(String[] args) {
context = SpringApplication.run(FactorybeanDemoApplication.class, args);
TestA testA = (TestA)context.getBean("0");
testA.print();
TestB testB = (TestB)context.getBean("1");
testB.print();
}
}
3.3 统一 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.factorybean</groupId>
<artifactId>factorybean-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>factorybean-demo</name>
<description>factorybean注入方式 project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4、源码分析
5、参考文献
https://zhuanlan.zhihu.com/p/653695574
https://blog.csdn.net/u014365523/article/details/118683004
https://blog.csdn.net/f5465245/article/details/123551991