重写并自定义依赖的原生的Bean方法

简介: 重写并自定义依赖的原生的Bean方法

转载请注明出处:

  在项目开发过程中,往往是直接应用很多jar包中依赖且声明好的Bean,拿来即用,但很多场景也需要对这些原生的Bean 进行自定义,定制化封装,这样在项目使用的过程中,可以使用自定义的Bean,而不是原生的Bean。下面总结了几种定制化原生Bean 的几种方式:

1. 在项目中创建同包同类名的类

    这种方式使用较少,因为项目中的包路径根据开发规范是根据业务名自定义的包路径

2.使用 @Primary 注解,或  @Qualifier 注解,定义Bean 的优先级或使用时,指定Bean

  • @Primary 优先考虑,优先考虑被注解的对象注入
  • @Qualifier 名字声明,声明后对名字进行使用

  当一个类有多个Bean的实例时,可以在 Bean 的实现类中 使用 @Primary 注解声明Bean 的优先级,在使用过程中,spring则默认加载该类实例化出的Bean。而 @Qualifiler 注解先声明后使用,相当于多个实现起多个不同的名字,注入时候告诉我你要注入哪个;

  @Primary 在源码中使用的示例: spring-cloud-starter-gateway 3.1.1 版本中的  GatewayAutoConfiguration 中的源码

@Bean
    @Primary
    public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
        return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
    }

  @Qualiflier 注解使用,当一个类有多个Bean 实例时,在使用 Bean 时,通过 @Qualiflier 制定Bean

@Service("employeeserver")
public class EmployeeServiceImpl implements EmployeeService {
    public EmployeeDto getEmployeeById(Long id) {
        return new EmployeeDto();
    }
}
 
@Service("manageserver")
public class ManagServiceImpl implements EmployeeService {
    public ManagerDto getEmployeeById(Long id) {
        return new ManagerDto();
    }
}

  使用:

@Controller
@RequestMapping("/emplayee")
public class EmployeeInfoControl {
    
    @Autowired
    @Qualifier("employeeserver")
    EmployeeService employeeService;
    
    @RequestMapping(params = "method=showEmplayeeInfo")
    public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response){
       ***********************
       *******************
    }

 

3. 使用 @ComponentScan 里面的 excludeFilters 排除不需要加载的类

  示例如下,排除 MyTestFilter 类

@SpringBootApplication
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})})
public class TestApplication {
  ...
}

  这里需要注意的是,可以定义一个与原生相同的Bean,但在 上面引包的时候,需要引入的包路径是要排除的包路径,这样自定义的相同的类就可以加载到容器中,原生的Bean 则不会加载。

  这种方式也是常用的方式;

 

4.使用 @Bean 注解覆盖原生的Bean

  该场景针对,框架jar包中有@ConditionalOnMissingBean注解,这种注解是说明如果你也创建了一个一样的Bean则框架就不自己再次创建这个bean了,这样你可以覆写自己的bean。

  直接继承要覆盖的类,自己重写里面方法,使用@Component注入到 spring 中去:

  spring-cloud-starter-gateway 3.1.1 版本中的  GatewayAutoConfiguration 中的源码对  HttpClientFactory  的定义

@Bean
        @ConditionalOnMissingBean({HttpClient.class, HttpClientFactory.class})
        public HttpClientFactory gatewayHttpClientFactory(HttpClientProperties properties, ServerProperties serverProperties, List<HttpClientCustomizer> customizers) {
            return new HttpClientFactory(properties, serverProperties, customizers);
        }

  重新自定义 该类的方法为:直接继承要覆盖的类,自己重写里面方法,使用@Component注入到spring中去

package my.test.gateway.config;
@Component
public class HttpClientFactory extends AbstractFactoryBean<HttpClient> {
    protected final HttpClientProperties properties;
    protected final ServerProperties serverProperties;
    protected final List<HttpClientCustomizer> customizers;
    public HttpClientFactory(HttpClientProperties properties, ServerProperties serverProperties, List<HttpClientCustomizer> customizers) {
        this.properties = properties;
        this.serverProperties = serverProperties;
        this.customizers = customizers;
    }
    .....  
}

 

5. 使用BeanDefinitionRegistryPostProcessor

  使用 Spring 提供的 Bean 后置处理器,进行自定义的Bean 加载;

package com.mytest.config.beantest.register;
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.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
 * @author amdin
*/
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        logger.info("bean 定义查看和修改...");
        String beanName = "myTestService";
        // 先移除原来的bean定义
        beanDefinitionRegistry.removeBeanDefinition(beanName);
        // 注册我们自己的bean定义
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(MyTestServiceIpml.class);
        // 如果有构造函数参数, 有几个构造函数的参数就设置几个  没有就不用设置
        beanDefinitionBuilder.addConstructorArgValue("构造参数1");
        beanDefinitionBuilder.addConstructorArgValue("构造参数2");
        beanDefinitionBuilder.addConstructorArgValue("构造参数3");
        // 设置 init方法 没有就不用设置
        beanDefinitionBuilder.setInitMethodName("init");
        // 设置 destory方法 没有就不用设置
        beanDefinitionBuilder.setDestroyMethodName("destory");
        // 将Bean 的定义注册到Spring环境
        beanDefinitionRegistry.registerBeanDefinition("myTestService", beanDefinitionBuilder.getBeanDefinition());
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        // bean的名字为key, bean的实例为value
        Map<String, Object> beanMap = configurableListableBeanFactory.getBeansWithAnnotation(RestController.class);
        logger.info("所有 RestController 的bean {}", beanMap);
    }
}

 

  最常见的重写自定义Bean 的方式为以上的 2,3,4 三种方式,通过以上方式就可以实现重写并自定义原生的Bean;

 

标签: spring cloud

目录
相关文章
|
6月前
|
数据安全/隐私保护 流计算
可以创建一个自定义的`AssignerWithPeriodicWatermarks`实现类
可以创建一个自定义的`AssignerWithPeriodicWatermarks`实现类
76 2
|
资源调度 前端开发 算法
前端依赖版本重写指南
感谢神奇的 Semver 动态规则,npm 社区经常会发生依赖包更新后引入破坏变更的情况(应用没有使用依赖锁的话),而应用开发者就要在自己的依赖声明里先临时绕过,避免安装到有问题的版本,如果是一级依赖,只需要改 package.json 的声明就可以了,但如果是子依赖,就需要进行版本重写(overrides/resolution)了。本文是一篇针对版本重写功能的指南性文章,当你遇到如下的问题时,就可以按照对应的依赖重写语法,解决这些依赖问题了。
5798 1
前端依赖版本重写指南
|
API
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
本篇文章接前一篇,建议可以先看前篇文章,再看本文,会有更好的效果。前一篇跳转链接:https://www.cnblogs.com/weskynet/p/15046999.html
635 0
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
|
4月前
|
Java Spring 容器
循环依赖问题之实例化Bean是通过如何实现的
循环依赖问题之实例化Bean是通过如何实现的
|
6月前
|
Java 微服务
|
图形学
Unity构造器注入+配置文件小实例
Unity构造器注入+配置文件小实例
|
6月前
|
Java Spring 容器
面试题:Spring框架中,一个组件是怎样向自己内部注入组件的
面试题:Spring框架中,一个组件是怎样向自己内部注入组件的
32 0
|
6月前
|
设计模式 Java 数据库连接
面试题:一个组件向自己内部注入组件有哪些方法?
面试题:一个组件向自己内部注入组件有哪些方法?
48 0
|
6月前
|
Java Maven
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
52 0
|
6月前
|
Java Maven
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
@ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean
42 0