场景

有些情况下,不能直接使用BEAN的方式:

@Bean(name = "storage")
public DataSourceProxy storageDataSourceProxy(@Qualifier("originStorage") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}

比如有些情况下,需要将BEAN 动态加入SPRING 容器中,但是上面的方式是固定的,实现不了在容器中动态注册BEAN。

实现方式

增加一个动态注册工具类:

package com.redxun.common.utils;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext; public class ManualRegistBeanUtil { /**
* 主动向Spring容器中注册bean
*
* @param applicationContext Spring容器
* @param name BeanName
* @param clazz 注册的bean的类性
* @param args 构造方法的必要参数,顺序和类型要求和clazz中定义的一致
* @param <T>
* @return 返回注册到容器中的bean对象
*/
public static <T> T registerBean(ConfigurableApplicationContext applicationContext, String name, Class<T> clazz,
Object... args) {
if(applicationContext.containsBean(name)) {
Object bean = applicationContext.getBean(name);
if (bean.getClass().isAssignableFrom(clazz)) {
return (T) bean;
} else {
throw new RuntimeException("BeanName 重复 " + name);
}
}
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
for (Object arg : args) {
beanDefinitionBuilder.addConstructorArgValue(arg);
}
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) applicationContext.getBeanFactory();
beanFactory.registerBeanDefinition(name, beanDefinition);
return applicationContext.getBean(name, clazz);
} }
applicationContext:spring 容器上下文

name:bean 的名称
clazz:需要注入的类
args : 类的构造参数。

注入无依赖的Bean

编写代码:

import lombok.extern.slf4j.Slf4j;

import java.util.Random;

@Slf4j
public class ManualBean { private int id;
private String name; public ManualBean() {
Random random = new Random();
id = random.nextInt(100);
} public ManualBean(String msg) {
this.name=msg;
} public String print( ) {
return "[ManualBean] print : " + name + " id: " + id;
}
}

注入测试:

import com.redxun.common.utils.ManualRegistBeanUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component; @Component
public class BeanRegisterAutoConf { public BeanRegisterAutoConf(ApplicationContext applicationContext) {
System.out.println("BeanRegisterAutoConf init: " + System.currentTimeMillis());
registerManualBean((ConfigurableApplicationContext) applicationContext);
} private void registerManualBean(ConfigurableApplicationContext applicationContext) {
// 主动注册一个没什么依赖的Bean
ManualBean manualBean = ManualRegistBeanUtil.registerBean(applicationContext, "manualBean", ManualBean.class,"RAY");
manualBean.print(); } }

这里使用了构造参数的方式进行注入。

测试注入是否可用

编写测试用例

@Test
public void testRegseterBean(){
ManualBean bean= SpringUtil.getBean("manualBean");
String str= bean.print();
System.err.println(str);
}

注入有依赖的BEAN

import org.springframework.beans.factory.annotation.Autowired;

import java.util.Random;

public class ManualDIBean {

    private int id;

    @Autowired
private OriginBean originBean; private String name; public ManualDIBean(String name) {
Random random = new Random();
this.id = random.nextInt(100);
this.name = name;
} public String print(String msg) {
String o = originBean.print(" call by ManualDIBean! ");
return "[ManualDIBean] print: " + msg + " id: " + id + " name: " + name + " originBean print:" + o;
}
}

这里注入了OriginBean bean。

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Slf4j
@Component
public class OriginBean { private LocalDateTime time; public OriginBean() {
time = LocalDateTime.now();
} public String print(String msg) {
return "[OriginBean] print msg: " + msg + ", time: " + time;
}
}

测试注册BEAN

@Component
public class BeanRegisterAutoConf { public BeanRegisterAutoConf(ApplicationContext applicationContext) {
System.out.println("BeanRegisterAutoConf init: " + System.currentTimeMillis());
registerManualBean((ConfigurableApplicationContext) applicationContext);
} private void registerManualBean(ConfigurableApplicationContext applicationContext) {
// manualDIBean 内部,依赖由Spring容器创建的OriginBean
ManualDIBean manualDIBean = ManualRegistBeanUtil.registerBean(applicationContext, "manualDIBean",
ManualDIBean.class, "依赖OriginBean的自定义Bean");
manualDIBean.print("test print manualDIBean");
}
}

编写单元测试从容器中获取bean。

@Test
public void testRegseterBean(){
ManualDIBean bean= SpringUtil.getBean("manualDIBean");
String str= bean.print("Hello");
System.err.println(str);
}
 

SPRING 动态注册BEAN的更多相关文章

  1. Spring动态注册bean实现动态多数据源

    Spring动态注册bean实现动态多数据源 http://blog.csdn.net/littlechang/article/details/8071882

  2. 180804-Spring之动态注册bean

    Spring之动态注册bean 什么场景下,需要主动向Spring容器注册bean呢? 如我之前做个的一个支持扫表的基础平台,使用者只需要添加基础配置 + Groovy任务,就可以丢到这个平台上面来运 ...

  3. SpringBoot27 JDK动态代理详解、获取指定的类类型、动态注册Bean、接口调用框架

    1 JDK动态代理详解 静态代理.JDK动态代理.Cglib动态代理的简单实现方式和区别请参见我的另外一篇博文. 1.1 JDK代理的基本步骤 >通过实现InvocationHandler接口来 ...

  4. spring动态修改bean

    spring动态修改bean @RequestMapping("ok") public Object test2(){ ApplicationContext application ...

  5. spring中注册bean(通过代码动态注册)

    看公司的源代码,在一个类中使用到了BeanDefinitionBuilder这个类,在学习之后才知道在项目中可能没有注册bean,在使用的时候才会进行注册,就涉及到了动态bean的注册,所以,在文章中 ...

  6. 【Spring Boot】Spring Boot之使用ImportBeanDefinitionRegistrar类实现动态注册Bean

    一.ImportBeanDefinitionRegistrar类介绍 ImportBeanDefinitionRegistrar类通过其他@Configuration类通过@Import的方式来加载, ...

  7. Spring-IOC BeanFactory运行时动态注册bean

    在spring运行时,动态的添加bean,dapeng框架在解析xml的字段时,使用到了动态注册,注册了一个实现了FactoryBean类! 定义一个没有被Spring管理的Controller pu ...

  8. spring 手动注册bean

    //将applicationContext转换为ConfigurableApplicationContext ConfigurableApplicationContext configurableAp ...

  9. 【Spring Boot】Spring Boot之使用ImportSelector类实现动态注册Bean

    一.ImportSelector类介绍     可以通过指定的选择条件来决定哪些类被注册到Spring中.与ImportBeanDefinitionRegistrar类功能相似,通过@Import的方 ...

  10. spring动态添加bean

    不知道大家想过没有,我们使用mybatis的时候只要写接口和配置上一个sql语句就可以了,单从代码的角度来看,这是不合理的. 所以我们通常在service里面注入的mapper它其实是一个代理对象 ​ ...

随机推荐

  1. 即构 UIKits 重磅发布!高效开发与自定义UI兼备,打造互动场景新标杆

    即构UIKits上线,新一代场景化实时互动SDK! 即构科技发布了首款面向中小团队的整合型实时互动产品UIKits , 基于场景化最佳实践,整合RTC.IM.直播.美颜等多款产品,打造了音视频通话UI ...

  2. 全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数

    全网最适合入门的面向对象编程教程:48 Python 函数方法与接口-位置参数.默认参数.可变参数和关键字参数 摘要: 在 Python 中,函数可以接受多种不同类型的参数,包括位置参数.默认参数.可 ...

  3. 阿里面试官常问的TCP和UDP,你真的弄懂了吗?

      前  言 作为软件测试,大家都知道一些常用的网络协议是我们必须要了解和掌握的,面试的时候面试官也非常喜欢问一些协议相关的问题,其中有两个协议因为非常基础,出现的频率非常之高,分别是 "T ...

  4. Windows NoiLinux

    在 Windows 下使用 NoiLinux ubuntu-noi-v2.0.iso 下载 ubuntu-noi-v2.0.iso 打开 VMWare,创建新的虚拟机 -> 自定义(高级)-&g ...

  5. 分布式执行引擎Ray-部署

    1. Ray集群 Ray 有多种部署模式,包括单机,k8s,VM等. 在单机下,可以直接用ray.init来快速启动ray的运行环境,但是如果要在多节点上执行,则必须先部署Ray Cluster. 一 ...

  6. .Net技术栈

    一.后端 1. 框架 C# 异步多线程 委托 事件 标准事件模式 泛型 特性 反射 Linq Lambda Expression表达式树 PLinq IO文件操作 XML操作 .Net IOC/DI依 ...

  7. typeof typeof 'texs'是什么类型

    typeof '12' 返回  'string' 是字符串类型  :

  8. 导入员工 excel 批量上传

    1. 安装 包  npm i xlsx   yarn add xlsx  2. 封装一个上传的组件 src/components/UploadExcel/index.vue code : <te ...

  9. 程序员开发利器:Your Commands网站上线

    程序员开发利器:Your Commands网站上线 先上链接: https://www.ycmds.cc 背景 各种命令行工具是我们IT行业日常工作离不开的,但是对于命令行工具的使用有一个痛点:文档上 ...

  10. mysql进阶-索引篇

    索引(SQL主要的优化方式) 介绍: 索引(index)是帮助MySQL高效获取数据的数据结构(有序).在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据 ...