• 重写并自定义依赖的原生的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 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 customizers) {
                return new HttpClientFactory(properties, serverProperties, customizers);
            }
    复制代码

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

    复制代码
    package my.test.gateway.config;

    @Component
    public class HttpClientFactory extends AbstractFactoryBean { protected final HttpClientProperties properties; protected final ServerProperties serverProperties; protected final List customizers; public HttpClientFactory(HttpClientProperties properties, ServerProperties serverProperties, List 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 beanMap = configurableListableBeanFactory.getBeansWithAnnotation(RestController.class);
            logger.info("所有 RestController 的bean {}", beanMap);
        }
    }
    复制代码

     

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

     

  • 相关阅读:
    千亿母婴辅食赛道崛起,建立和完善行业标准迫在眉睫
    剑指offer-数据结构二
    dma epoll kernel thread
    Redis最佳实践(上)
    面向大数据存算分离场景的数据湖加速方案
    【计算机毕业设计】PHP基于微信小程序实现快去印的实现与开发(源码+需求文档)
    电脑组装教程分享!
    Git常用规范
    MySQL概念
    【模型提分tricks】Adversarial Weight Perturbation(AWP)对抗训练
  • 原文地址:https://www.cnblogs.com/zjdxr-up/p/16533930.html