场景

有些情况下,不能直接使用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. 系统编程-进程-先后fork或open一个文件的区别

    关联博文: 当文件操作遇上fork Linux内核的文件结构体 struct file { ......... struct path f_path; //文件的路径 #define f_dentry ...

  2. postgre基于行数的外连接及python连接postgre数据库

    外连接 左外/右外连接 左外连接:左表全部出现在结果集中,若右表无对应记录,则相应字段为NULL left join ... on 条件 右外连接:右表全部出现在结果集中,若左表无对应记录,则相应字段 ...

  3. SQL Server的Descending Indexes降序索引

    SQL Server的Descending Indexes降序索引 背景索引是关系型数据库中优化查询性能的重要手段之一.对于需要处理大量数据的场景,合理的索引策略能够显著减少查询时间. 特别是在涉及多 ...

  4. LeetCode 327. Count of Range Sum 区间和的个数

    给定一个整数数组 nums,返回区间和在 [lower, upper] 之间的个数,包含 lower 和 upper.区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 ...

  5. Linux调度器:进程优先级

    一.前言 本文主要描述的是进程优先级这个概念.从用户空间来看,进程优先级就是nice value和scheduling priority,对应到内核,有静态优先级.realtime优先级.归一化优先级 ...

  6. signalR的身份认证

  7. 在mac上配置nginx 并将前端的打包文件运行

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  8. 云原生周刊:Kubernetes v1.28 新特性一览 | 2023.8.14

    推荐一个 GitHub 仓库:Fast-Kubernetes. Fast-Kubernetes 是一个涵盖了 Kubernetes 的实验室(LABs)的仓库.它提供了关于 Kubernetes 的各 ...

  9. 利用 Kubernetes 内置 PodTemplate 管理 Jenkins 构建节点

    作者:Rick Jenkins 可以很好地与 Kubernetes 集成,不管是控制器(controller)还是构建节点(agent),都能以 Pod 的形式运行在 Kubernetes 上. 熟悉 ...

  10. SpringBoot 2.3 升级到 SpringBoot 2.7 爬坑-- SpringDoc & Swagger

    目录 POM yml 配置自定义的 OpenAPI 规范 拦截器去除 swagger 的接口验证 模型 Controller 配置 常用注解 注意:Swagger支持SpringBoot2.0但不支持 ...