SPRING 動態注冊BEAN


場景

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

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM