场景

有些情况下,不能直接使用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. MDC – Text field

    前言 Angular Material 只有 Form field, 但 Material Design 有份 Text field 和 Form field, Form field 是给 check ...

  2. Servlet——简介

    Servlet    快速入门   1.创建web项目,导入Servlet依赖坐标 <dependencies> <dependency> <groupId>jav ...

  3. .NET 跨平台工业物联网网关解决方案

    前言 随着工业4.0时代的到来,物联网技术正在以前所未有的速度改变着我们的生产和生活方式.本文给大家介绍一个基于 .NET 6 开发的跨平台工业物联网网关解决方案. 工业物联网(IIoT)成为了连接物 ...

  4. 2021年11月墨天轮国产数据库排行榜:openGauss闯入前三,Kingbase流行度与日俱增,TDengine厚积薄发

    2021年11月的国产数据库流行度排行榜已在墨天轮发布,本月共有163家数据库参与排名.就前15名的总体情况来看,除openGauss反超OceanBase闯入前三,TDengine厚积薄发来到第15 ...

  5. 墨天轮访谈 | 叶金荣:GreatSQL开源社区——做中国广受欢迎的开源数据库

    分享嘉宾:叶金荣 万里数据库开源生态负责人 整理:墨天轮社区 导读 大家好,我是来自万里数据库的叶金荣,GreatSQL开源社区的愿景是做中国广受欢迎的开源数据库,这也是我今天分享的主题. Great ...

  6. threejs 父元素 相对位置 position 网格对象

    设置position都是相对于父元素的位置设置的 // 导入 threejs import * as THREE from "three"; import { OrbitContr ...

  7. css flex布局的使用

    felx弹性布局 display:flex; 属性值 flex-direction 属性定义容器要在哪个方向上堆叠 flex 项目.默认为水平方向 row, column 值设置垂直方向.如:flex ...

  8. 前台sessionStorage存取对象注意事项

    一.概述 使用sessionStorage存取全局数据: 语法: sessionStorage.setItem("key",value); object = sessionStor ...

  9. 工作中的技术总结_ form表单使用注意事项之form触发后台提交事件 _20220127

    工作中的技术总结_ form表单使用注意事项之form触发后台提交事件 _20220127 如无必要不要使用 form标签 来作为组件的父节点 事件过程: 项目使用的是 spring + jsp 的框 ...

  10. 轻量级网络-MobileNetv1 论文解读

    1.相关工作 标准卷积 分组卷积 从 Inception module 到 depthwise separable convolutions 2.MobileNets 结构 2.1,深度可分离卷积 D ...