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