场景

有些情况下,不能直接使用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. 物体检测序列之一:NMS

    IoU (Intersection over Union),交并比,是衡量物体检测模型在特定数据集上检测效果好坏的一个常用的标准,通常情况下,想要通过IoU来衡量物体检测模型好坏需要具备以下几点: 1 ...

  2. 前端项目通过 Nginx 发布至 Linux,并通过 rewrite 配置访问后端接口

    〇.前言 本文通过将 arco 框架的前端项目,部署至 CentOS 7,并访问同服务器的 WebAPI 接口,来简单演示一下,如何将前端项目发布至 Linux 系统. 关于 ASP.NET WebA ...

  3. WiFi基础(四):WiFi工作原理及WiFi接入过程

    liwen01 2024.09.16 前言 802.11 无线 WiFi 网有三类帧:数据帧.管理帧.控制帧.与有线网相比,无线 WiFi 网会复杂很多.大部分应用软件开发对 WiFi 的控制帧和管理 ...

  4. HTTP——请求数据格式

    请求数据格式   

  5. shell脚本参数读取列表文件,循环执行时,要注意这个列表文件转换成 unix 格式

    当报一些很奇怪的错,比如报错多了一个空格,但 vim 看打开没有,比如: 或者肉眼看上去路径正常,但却报路径不存在: 这种时候要使用 dos2unix 工具,把这个列表文件转换一下:

  6. BOOST 环形队列circular_buffer

    BOOST库的环形队列比较灵活,前插或后插,删除队首或删除队尾元素,都支持. 只贴代码: #include <boost/circular_buffer.hpp> #include < ...

  7. C# 开源浏览器性能提升,体验Chrome级速度

    前言 使用 C# 和 CefSharp 开发的全功能网页浏览器. 项目介绍 SharpBrowser 是目前最快的开源 C# 网页浏览器! 采用了轻量级的 CEF 渲染器,在呈现网页时甚至比 Goog ...

  8. [TK] 盖房子 hzoi-tg#262

    同机房大佬也写了这题的 题解. 通解分析 此类问题我通常喜欢归纳成一类,即阻碍联通的坐标DP. 既然是阻碍联通,那么此类问题的通用思路是这样的: 首先将dp数组图形化. 一般用一个特定图形上的特定点来 ...

  9. YAML 文件基本语法格式(十四)

    一.YAML 文件基本语法格式 前面我们得 Kubernetes 集群已经搭建成功了,现在我们就可以在集群里面来跑我们的应用了.要在集群里面运行我们自己的应用,首先我们需要知道几个概念. 第一个当然就 ...

  10. HarmonyOS NEXT 底部选项卡功能

    在HarmonyOS NEXT中使用ArkTS实现一个完整的底部选项卡功能,可以通过以下几个步骤来完成: 创建Tabs组件:使用Tabs组件来创建底部导航栏,并通过barPosition属性设置其位置 ...