场景
有些情况下,不能直接使用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);
}