在开发的过程中,经常引入别人写的jar包实现某功能。而别的jar包一般都自动注入Spring容器中,假设都是通过@Bean、@Service或@Component注入的,并且没有加入@ConditionalXXX等注解,导致无法替换掉别人的实现,假设这时就想替换掉,那该如何实现呢?
- BeanDefinitionRegistry 是一个接口,它定义了关于 BeanDefinition 的注册、移除、查询等一系列的操作。
- BeanDefinitionRegistryPostProcessor接口常用于给接口动态添加代理类。
- BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor 都是spring的后置处理器,但是两个类的侧重点不一样,
- BeanDefinitionRegistryPostProcessor 侧重于创建自定义的bd 而 BeanFactoryPostProcessor侧重于对已有bd属性的修改。
- BeanDefinitionRegistryPostProcessor 先于 BeanFactoryPostProcessor 执行
参考
替换Spring容器中已经存在的Bean
Spring(五)核心容器 - 注册 Bean、BeanDefinitionRegistry 简介
Spring之27:BeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor作用及加载顺序
BeanDefinitionRegistryPostProcessor的作用及和 BeanFactoryPostProcessor 的区别
BeanDefinitionRegistryPostProcessor——动态注册Bean到Spring容器
代码
pom
<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.1.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.3.8</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
验证代码-java
接口
/**
* 替换Spring容器中已经存在的Bean-接口
*
* @author z.y.l
* @version v1.0
* @date 2022/10/8
*/publicinterfaceDemoMasterService{/**
* 主函数
*/voidinit();}
源实现类
importxx.xxx.spring.boot.branch.service.DemoMasterService;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.stereotype.Service;importjavax.annotation.PostConstruct;/**
* 替换Spring容器中已经存在的Bean-主
*
* @author z.y.l
* @version v1.0
* @date 2022/10/8
*/@Service("demoMasterService")publicclassDemoMasterServiceImplimplementsDemoMasterService{privatefinalLogger logger =LoggerFactory.getLogger(DemoMasterServiceImpl.class);@Overridepublicvoidinit(){
logger.info("替换Spring容器中已经存在的Bean-主");}@PostConstructprivatevoidpost(){
logger.info("类初始化-主》》》》》");}}
替代类
importxx.xxx.spring.boot.branch.service.DemoMasterService;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjavax.annotation.PostConstruct;/**
* 替换Spring容器中已经存在的Bean-替代类,不使用 @Service
*
* @author z.y.l
* @version v1.0
* @date 2022/10/8
*/publicclassDemoReplaceServiceImplimplementsDemoMasterService{privatefinalLogger logger =LoggerFactory.getLogger(DemoReplaceServiceImpl.class);@Overridepublicvoidinit(){
logger.info("替换Spring容器中已经存在的Bean-替代");}@PostConstructprivatevoidpost(){
logger.info("类初始化-替代》》》》》");}}
实现 spring 的类
BeanDefinitionRegistryPostProcessor
,进行容器内类的偷天换日。
importxx.xxx.spring.boot.branch.service.impl.DemoReplaceServiceImpl;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;importorg.springframework.beans.factory.support.BeanDefinitionRegistry;importorg.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;importorg.springframework.beans.factory.support.GenericBeanDefinition;importorg.springframework.stereotype.Component;/**
* 替换 管理类
*
* @author z.y.l
* @version v1.0
* @date 2022/10/8
*/@ComponentpublicclassOverrideExistsBeanDefRegistryPostProcessorimplementsBeanDefinitionRegistryPostProcessor{privatefinalLogger logger =LoggerFactory.getLogger(OverrideExistsBeanDefRegistryPostProcessor.class);privatefinalstaticString NAME ="demoMasterService";@OverridepublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)throwsBeansException{String[] names = registry.getBeanDefinitionNames();
logger.info("替换 管理类>>>>>,总注册类:{}",names.length);if(registry.containsBeanDefinition(NAME)){String beanName = registry.getBeanDefinition(NAME).getBeanClassName();
logger.info("替换 管理类,替换目标类-移除源实现类,{}",beanName);
registry.removeBeanDefinition(NAME);GenericBeanDefinition definition =newGenericBeanDefinition();
logger.info("替换 管理类,替换目标类-注入替代实现类");
definition.setBeanClass(DemoReplaceServiceImpl.class);
registry.registerBeanDefinition(NAME,definition);
beanName = registry.getBeanDefinition(NAME).getBeanClassName();
logger.info("替换 管理类,替换目标类-最终实现类,{}",beanName);}}@OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throwsBeansException{}}
测试
c.z.s.b.b.c.OverrideExistsBeanDefRegistryPostProcessor [OverrideExistsBeanDefRegistryPostProcessor.java:31] =.= 替换 管理类>>>>>,总注册类:131
c.z.s.b.b.c.OverrideExistsBeanDefRegistryPostProcessor [OverrideExistsBeanDefRegistryPostProcessor.java:34] =.= 替换 管理类,替换目标类-移除源实现类,cn.zyl.spring.boot.branch.service.impl.DemoMasterServiceImpl
c.z.s.b.b.c.OverrideExistsBeanDefRegistryPostProcessor [OverrideExistsBeanDefRegistryPostProcessor.java:37] =.= 替换 管理类,替换目标类-注入替代实现类
c.z.s.b.b.c.OverrideExistsBeanDefRegistryPostProcessor [OverrideExistsBeanDefRegistryPostProcessor.java:41] =.= 替换 管理类,替换目标类-最终实现类,cn.zyl.spring.boot.branch.service.impl.DemoReplaceServiceImpl
o.s.b.w.e.t.TomcatWebServer [TomcatWebServer.java:108] =.= Tomcat initialized with port(s): 8080 (http)
...
c.z.s.b.b.s.i.DemoReplaceServiceImpl [DemoReplaceServiceImpl.java:24] =.= 类初始化-替代》》》》》
END
版权归原作者 privateobject 所有, 如有侵权,请联系我们删除。