SpringBoot替换容器内注入的Bean

29 篇文章 0 订阅
23 篇文章 0 订阅

在开发的过程中,经常引入别人写的jar包实现某功能。而别的jar包一般都自动注入Spring容器中,假设都是通过@Bean、@Service或@Component注入的,并且没有加入@ConditionalXXX等注解,导致无法替换掉别人的实现,假设这时就想替换掉,那该如何实现呢?

  1. BeanDefinitionRegistry 是一个接口,它定义了关于 BeanDefinition 的注册、移除、查询等一系列的操作。
  2. 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
 */
public interface DemoMasterService {
    /**
     * 主函数
     */
    void init();
}

源实现类

import xx.xxx.spring.boot.branch.service.DemoMasterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

/**
 * 替换Spring容器中已经存在的Bean-主
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/10/8
 */
@Service("demoMasterService")
public class DemoMasterServiceImpl implements DemoMasterService {
    private final Logger logger = LoggerFactory.getLogger(DemoMasterServiceImpl.class);
    @Override
    public void init() {
        logger.info("替换Spring容器中已经存在的Bean-主");
    }
    @PostConstruct
    private void post(){
        logger.info("类初始化-主》》》》》");
    }
}

替代类

import xx.xxx.spring.boot.branch.service.DemoMasterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;

/**
 * 替换Spring容器中已经存在的Bean-替代类,不使用 @Service
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/10/8
 */
public class DemoReplaceServiceImpl implements DemoMasterService {
    private final Logger logger = LoggerFactory.getLogger(DemoReplaceServiceImpl.class);
    @Override
    public void init() {
        logger.info("替换Spring容器中已经存在的Bean-替代");
    }
    @PostConstruct
    private void post(){
        logger.info("类初始化-替代》》》》》");
    }
}

实现 spring 的类 BeanDefinitionRegistryPostProcessor,进行容器内类的偷天换日。

import xx.xxx.spring.boot.branch.service.impl.DemoReplaceServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

/**
 * 替换 管理类
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/10/8
 */
@Component
public class OverrideExistsBeanDefRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    private final Logger logger = LoggerFactory.getLogger(OverrideExistsBeanDefRegistryPostProcessor.class);
    private final static String NAME = "demoMasterService";
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        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 = new GenericBeanDefinition();
            logger.info("替换 管理类,替换目标类-注入替代实现类");
            definition.setBeanClass(DemoReplaceServiceImpl.class);
            registry.registerBeanDefinition(NAME,definition);
            beanName = registry.getBeanDefinition(NAME).getBeanClassName();
            logger.info("替换 管理类,替换目标类-最终实现类,{}",beanName);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
}

测试

在这里插入图片描述

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

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用SpringBoot的过程中,获取容器中的bean可以使用@Autowired注解或者通过ApplicationContext获取。其中,@Autowired注解可以自动注入容器中的bean实例,而ApplicationContext则提供了多种方式来获取bean。 使用@Autowired注解获取bean,只需要在需要使用bean的属性或者构造函数上标注该注解,并且确保该bean在程序启动时已经注入容器中。例如: ```java @Service public class MyService { //... } @RestController public class MyController { @Autowired private MyService myService; //... } ``` 在上面的例子中,MyController类中的myService属性使用@Autowired注解进行了注入SpringBoot会自动从容器中查找类型为MyService的bean,并将其注入到属性中。 除了@Autowired注解,还可以使用ApplicationContext来获取bean实例。具体来说,可以通过@ComponentScan注解将指定包下的类扫描并注册到Spring容器中,然后使用ApplicationContext来获取这些bean。例如: ```java @SpringBootApplication @ComponentScan(basePackages = "com.example") public class MyApplication { //... } @Service public class MyService { //... } public class MyUtils { public static MyService getService() { ApplicationContext context = new AnnotationConfigApplicationContext(MyApplication.class); return context.getBean(MyService.class); } } ``` 在上面的例子中,MyApplication使用@ComponentScan注解来指定需要注册到容器中的类所在的包,然后在MyUtils中使用ApplicationContext来获取容器中的MyService实例。需要注意的是,在每次获取bean实例时都会创建一个新的ApplicationContext,因此可能会有性能上的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值