转载请注明出处:

  在项目开发过程中,往往是直接应用很多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;

重写并自定义依赖的原生的Bean方法的更多相关文章

  1. 解决Spring中singleton的Bean依赖于prototype的Bean的问题

    在spring bean的配置的时候,可能会出现一个singleton的bean依赖一个prototype的bean.因为singleton的bean只有一次初始化的机会,所以他们的依赖关系页只有在初 ...

  2. angular中自定义依赖注入的方法和decorator修饰

    自定义依赖注入的方法 1.factory('name',function () { return function(){ } }); 2.provider('name',function(){ thi ...

  3. 让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean

    让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean 问题描述 实现思路 思路一 [不符合要求] 思路二[满足要求] 思路三[未试验] 问题描述 目前我工作环境下,后端主要的框架 ...

  4. spring不依赖注入得到实体bean

    如题,我们一般用spring的ioc,通过配置注入接口得到这个实现类,现在通过研究公司平台框架发现还有一种方法得到spring文件配置的bean方法,举个例子(注:这个ApplicationConte ...

  5. NO.08--VUE之自定义组件添加原生事件

    前几篇给大家分享了我的业余的“薅羊毛”的经历,回归正题,讲回vue吧: 许多vue新手在工作开发中会遇到一个问题,直接使用 button 添加原生事件是没有问题的,但是使用自定义组件添加原生事件时,就 ...

  6. WPF 自定义依赖属性

      原博客地址:http://www.cnblogs.com/DebugLZQ/archive/2012/11/30/2796021.html    DependencyObject和Dependen ...

  7. WPF自定义依赖集合属性无法触发更新的问题

    通常WPF中通过继承UserControl的来快速创建自定义控件,最近项目上需要设计一个卫星星图显示控件,最终效果如下图所示.完成过程中遇到了自定义集合依赖属性无法触发更新通知的问题,在此记录一下,方 ...

  8. MSYS2是对MSYS的一个独立的重写,是基于当前的Cygwin和MinGW-w64重写的,以同原生的Windows软件有更好的交互性为目的

    MSYS2的官网:http://sourceforge.net/projects/msys2/ 官网的描述: Description MSYS2 is an independent rewrite o ...

  9. Asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

随机推荐

  1. 标注工具doccano导出数据为空的解决办法

    地址:https://github.com/taishan1994/doccano_export doccano_export 使用doccano标注工具同时导出实体和关系数据为空的解决办法.docc ...

  2. Spring Security之简单举例

    核心功能 Spring Security提供了三个核心的功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) 一个简单例子 默认情况 在前面的开发中,都是将spring securit ...

  3. 115_Power Pivot之HR薪酬计算:公积金、社保、个税、实发工资相关

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 1.之前写了一个关于入离调转的pp应用,现在个税新增专项附加扣除项目,借此写一个关于薪酬计算的案例: 2.本案例 ...

  4. CMake进行C/C++开发(linux下)

    开发环境配置 安装GCC,GDB sudo apt update # 通过以下命令安装编译器和调试器 sudo apt install build-essential gdb 安装成功确认 # 以下命 ...

  5. .net 获取IP地址的几种方式

    1.获取服务器IP地址: 1) Local_Addr var Local_Addr = Request.ServerVariables.Get("Local_Addr").ToSt ...

  6. java-去除html中的标签或者元素属性(正则表达式/jsoup)

    业务场景: 如一篇使用富文本编辑器编辑的新闻稿,需要在列表页面截取前200字作为摘要,此时需要去除html标签,截取真正的文本部分. /** * 删除Html标签 */public static St ...

  7. SQL中如何修改数据库名、表名、列名?

    文章目录 1.SQL中如何修改数据库的名字? 2.SQL中如何修改表的名字? 3.SQL中如何修改列的名字? 4.SQL中如何修改列的数据类型?(未完成,待续) 1.SQL中如何修改数据库名? 语法 ...

  8. Machine Learning With Go 第4章:回归

    4 回归 之前有转载过一篇文章:容量推荐引擎:基于吞吐量和利用率的预测缩放,里面用到了基本的线性回归来预测容器的资源利用情况.后面打算学一下相关的知识,译自:Machine Learning With ...

  9. Eclipse for Python开发环境部署

    Eclipse for Python开发环境部署 工欲善其事,必先利其器. 对开发人员来说,顺手的开发工具必定事半功倍.自学编程的小白不知道该选择那个开发工具,Eclipse作为一个功能强大且开源免费 ...

  10. 如何优化PlantUML流程图(时序图)

    这篇文章用来介绍,如何画出好看的流程图. 1. 选择合适的组件 1.1 plantuml官方提供的组件 1.2 加载图片 1.2.1 加载本地图片 1.2.2 加载网络图片 1.2.3 图片资源 2. ...