欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式

 更新時(shí)間:2022年07月15日 11:26:56   作者:北冥有只魚  
這篇文章主要為大家介紹了向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本文的大綱

從一個(gè)需求談起

這周遇到了這樣一個(gè)需求,從第三方的數(shù)據(jù)庫中獲取值,只是一個(gè)簡單的分頁查詢,處理這種問題,我一般都是在配置文件中配置數(shù)據(jù)庫的地址等相關(guān)信息,然后在Spring Configuration 注冊(cè)數(shù)據(jù)量連接池的bean,然后再將數(shù)據(jù)庫連接池給JdbcTemplate, 但是這種的缺陷是,假設(shè)填錯(cuò)了數(shù)據(jù)庫地址和密碼,或者換了數(shù)據(jù)庫的地址和密碼,在配置文件里面重啟之后,都需要重啟應(yīng)用。

我想能不能動(dòng)態(tài)的向Spring IOC容器中注冊(cè)和加載bean呢,項(xiàng)目在界面上填寫數(shù)據(jù)庫的地址、用戶名、密碼,存儲(chǔ)之后,將JdbcTemplate和另一個(gè)數(shù)據(jù)庫連接池加載到IOC容器中。答案是可以的,我經(jīng)過一番搜索寫出了如下代碼:

@Component
public class BeanDynamicRegister {
    private final ConfigurableApplicationContext configurableApplicationContext;
    public BeanDynamicRegister(ConfigurableApplicationContext configurableApplicationContext) {
        this.configurableApplicationContext = configurableApplicationContext;
    }
    /**
     * 此方法提供出去,供其他bean動(dòng)態(tài)的向IOC容器中注冊(cè)bean。
     * 代表使用構(gòu)造器給bean賦值
     *
     * @param beanName bean名
     * @param clazz    bean類
     * @param args     用于向bean的構(gòu)造函數(shù)中添加值 如果loadType是set,則要求傳遞map.map的key為屬性名,value為屬性值
     * @param <T>      返回一個(gè)泛型
     * @param loadType
     * @return
     */
    public <T> T registerBeanByLoadType(String beanName, Class<T> clazz, LoadType loadType, Object... args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        if (args.length > 0) {
            // 將參數(shù)加入到構(gòu)造函數(shù)中
            switch (loadType) {
                case CONSTRUCTOR:
                    for (Object arg : args) {
                        beanDefinitionBuilder.addConstructorArgValue(arg);
                    }
                    break;
                case SETTER:
                    Map<String, Object> propertyMap = (Map<String, Object>) args[0];
                    for (Map.Entry<String, Object> stringObjectEntry : propertyMap.entrySet()) {
                        beanDefinitionBuilder.addPropertyValue(stringObjectEntry.getKey(), stringObjectEntry.getValue());
                    }
                    break;
                default:
                    break;
            }
        }
        BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) configurableApplicationContext.getBeanFactory();
        beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
        return configurableApplicationContext.getBean(beanName, clazz);
    }
    public <T> T getBeanByName(String beanName,Class<T> requiredType){
        return  configurableApplicationContext.getBean(beanName,requiredType);
    }
    /**
     * 如果用戶換了地址和密碼,向IOC容器中移除bean。 重新注冊(cè)
     *
     * @param beanName
     */
    public void removeBean(String beanName) {
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) configurableApplicationContext.getBeanFactory();
        beanDefinitionRegistry.removeBeanDefinition(beanName);
    }
}
@SpringBootTest
class SsmApplicationTests {
    @Autowired
    private LoadBeanService loadBeanService;
    private NamedParameterJdbcTemplate jdbcTemplate;
    @Autowired
    private BeanDynamicRegister beanDynamicRegister;
    @Test
    public void test() {
        loadBeanService.loadDataSourceTest("root", "root");
        jdbcTemplate = beanDynamicRegister.getBeanByName("jdbcTemplateOne", NamedParameterJdbcTemplate.class);
        System.out.println("--------" + jdbcTemplate);
    }
}

結(jié)果: 

我們就到這里了嗎? 我們觀察一下上面將一個(gè)bean加載到Spring IOC容器里經(jīng)過了幾步:

  • BeanDefineBuilder 構(gòu)造BeanDefinition
  • 然后BeanDefinitionRegistry將其注冊(cè)到IOC容器中。(這一步事實(shí)上只完成了注冊(cè),還未完成Bean的實(shí)例化,屬性填充)

聯(lián)系我們前面的文章《Spring Bean 的生命周期》,我們將Spring 的生命周期理解為“Spring 給我們提供的一些擴(kuò)展接口,如果bean實(shí)現(xiàn)了這些這些接口,應(yīng)用在啟動(dòng)的過程中會(huì)回調(diào)這些接口的方法。” , 這個(gè)理解并不完善,缺少了解析BeanDefinition這個(gè)階段。

Spring Bean的生命周期再完善

BeanDefinition

那BeanDefinition是什么? BeanDefinition是一個(gè)接口,我們進(jìn)Spring 官網(wǎng)(https://docs.spring.io/spring...)大致看一下:

A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information, such as the initialization method, a static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values or add others as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.

bean 的定義信息可以包含許多配置信息,包括構(gòu)造函數(shù)參數(shù),屬性值和特定于容器的信息,例如初始化方法,靜態(tài)工廠方法名稱等。子 bean 定義可以從父 bean 定義繼承配置數(shù)據(jù)。子 bean 的定義信息可以覆蓋某些值,或者可以根據(jù)需要添加其他值。使用父 bean 和子 bean 的定義可以節(jié)省很多輸入(實(shí)際上,這是一種模板的設(shè)計(jì)形式)。

這段說的可能有點(diǎn)抽象, 你點(diǎn)BeanDefinition進(jìn)去,你就會(huì)發(fā)現(xiàn)有很多熟悉的面孔:

Bean的作用域: 單例,還是多例。

lazyInit是否是懶加載。

這些都是描述Spring Bean的信息,我們可以類比到Java中的類,每個(gè)類都會(huì)有class屬性,我們?cè)谂渲妙惢蛘選ml中的配置Bean的元信息,也被映射到這里。供IOC容器將Bean加入時(shí)使用。所以我們可以為對(duì)Spring Bean的生命周期的理解打一個(gè)補(bǔ)丁:

  • 從xml或配置類中解析BeanDefintion
  • BeanDefinition 注冊(cè),此時(shí)還未完成Bean的實(shí)例化。

我們可以打斷點(diǎn)來驗(yàn)證一下:

  • Bean 實(shí)例化
  • Bean的屬性賦值+依賴注入
  • Bean的初始化階段的方法回調(diào)
  • Bean的銷毀。

Bean 加入IOC容器的幾種方式

我們這里再來總結(jié)一下一個(gè)Bean注入Spring IOC容器的幾種形式:

啟動(dòng)時(shí)加入

  • 配置類: @Configuration+@Bean
  • 配置文件: xml

注解形式

  • @Component
  • @Service
  • @Controller
  • @Repository
  • @import
  • @Qualifier
  • @Resource
  • @Inject

運(yùn)行時(shí)加入

這三種最終都是通過BeanDefinitionRegistry來注入的,ImportBeanDefinitionRegistrar是一個(gè)接口,留給我們實(shí)現(xiàn)的方法如下:

default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
  • ImportBeanDefinitionRegistrar
  • 手動(dòng)構(gòu)造BeanDefinition注入(我們上面就是自己手動(dòng)構(gòu)造BeanDefinition注入)
  • 借助BeanDefinitionRegistryPostProcessor注入

? BeanDefinitionRegistryPostProcessor也是一個(gè)接口,留給我們實(shí)現(xiàn)的方法如下:

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

從spring容器中動(dòng)態(tài)添加或移除bean

public class DemoUtil {
    @Autowired
    private ApplicationContext applicationContext;
//添加bean
    public void addBean(String beanName, Class<?> beanClass) {
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
            beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
        }
    }
//移除bean
    public void removeBean(String beanName) {
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
        beanDefinitionRegistry.getBeanDefinition(beanName);
        beanDefinitionRegistry.removeBeanDefinition(beanName);
    }
}

參考資料

以上就是向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于Spring IOC 容器動(dòng)態(tài)注冊(cè)bean的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring?IOC容器Bean管理的完全注解開發(fā)放棄配置文件

    Spring?IOC容器Bean管理的完全注解開發(fā)放棄配置文件

    這篇文章主要為大家介紹了Spring?IOC容器的Bean管理完全注解開發(fā)放棄配置文件,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Java 如何使用Velocity引擎生成代碼

    Java 如何使用Velocity引擎生成代碼

    代碼生成器,可以有效減少編寫重復(fù)代碼,快速實(shí)現(xiàn)簡單的業(yè)務(wù)邏輯,也能讓我們的代碼保持一致。那目前,我們看到的代碼生成器,大部分是基于velocity引擎模板生成的,接下來我們就學(xué)習(xí)一下如何實(shí)現(xiàn)代碼生成器。
    2021-06-06
  • 基于zipoutputStream的簡單使用

    基于zipoutputStream的簡單使用

    這篇文章主要介紹了基于zipoutputStream的簡單使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring實(shí)戰(zhàn)之容器中的工程Bean用法示例

    Spring實(shí)戰(zhàn)之容器中的工程Bean用法示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之容器中的工程Bean用法,結(jié)合實(shí)例形式分析了Sring框架容器中的工程Bean相關(guān)配置、使用操作技巧,需要的朋友可以參考下
    2019-11-11
  • SWT(JFace)體驗(yàn)之GridLayout布局

    SWT(JFace)體驗(yàn)之GridLayout布局

    GridLayout 布局的功能非常強(qiáng)大,也是筆者常用的一種布局方式。GridLayout是網(wǎng)格式布局,它把父組件分成一個(gè)表格,默認(rèn)情況下每個(gè)子組件占據(jù)一個(gè)單元格的空間,每個(gè)子組件按添加到父組件的順序排列在表格中。
    2009-06-06
  • java實(shí)現(xiàn)字符串匹配求兩個(gè)字符串的最大公共子串

    java實(shí)現(xiàn)字符串匹配求兩個(gè)字符串的最大公共子串

    這篇文章主要介紹了java實(shí)現(xiàn)求兩個(gè)字符串最大公共子串的方法,詳細(xì)的描述了兩個(gè)字符串的最大公共子串算法的實(shí)現(xiàn),需要的朋友可以參考下
    2016-10-10
  • 如何使用IDEA 搭建 SpringCloud 項(xiàng)目

    如何使用IDEA 搭建 SpringCloud 項(xiàng)目

    所謂微服務(wù),就是要把整個(gè)業(yè)務(wù)模塊拆分成多個(gè)各司其職的小模塊,做到單一職責(zé)原則,不會(huì)重復(fù)開發(fā)相同的業(yè)務(wù)代碼,實(shí)現(xiàn)真正意義上的高內(nèi)聚、低耦合,這篇文章主要介紹了如何使用IDEA 搭建 SpringCloud 項(xiàng)目,需要的朋友可以參考下
    2023-11-11
  • java中匿名內(nèi)部類解讀分析

    java中匿名內(nèi)部類解讀分析

    本篇文章介紹了,java中匿名內(nèi)部類解讀分析。需要的朋友參考下
    2013-05-05
  • Java中生成隨機(jī)數(shù)的4種方式與區(qū)別詳解

    Java中生成隨機(jī)數(shù)的4種方式與區(qū)別詳解

    生成隨機(jī)數(shù)是我們?nèi)粘i_發(fā)經(jīng)常會(huì)遇到的一個(gè)功能,這篇文章主要給大家介紹了關(guān)于Java中生成隨機(jī)數(shù)的4種方式與區(qū)別、應(yīng)用場景的相關(guān)資料,4個(gè)方式分別是Random、ThreadLocalRandom、SecureRandom以及Math,需要的朋友可以參考下
    2021-06-06
  • 集群環(huán)境中使用ehcache_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    集群環(huán)境中使用ehcache_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了集群環(huán)境中使用ehcache的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評(píng)論