最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

向Spring IOC 容器動態(tài)注冊bean實現(xiàn)方式

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

本文的大綱

從一個需求談起

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

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

@Component
public class BeanDynamicRegister {
    private final ConfigurableApplicationContext configurableApplicationContext;
    public BeanDynamicRegister(ConfigurableApplicationContext configurableApplicationContext) {
        this.configurableApplicationContext = configurableApplicationContext;
    }
    /**
     * 此方法提供出去,供其他bean動態(tài)的向IOC容器中注冊bean。
     * 代表使用構造器給bean賦值
     *
     * @param beanName bean名
     * @param clazz    bean類
     * @param args     用于向bean的構造函數(shù)中添加值 如果loadType是set,則要求傳遞map.map的key為屬性名,value為屬性值
     * @param <T>      返回一個泛型
     * @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ù)加入到構造函數(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。 重新注冊
     *
     * @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);
    }
}

結果: 

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

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

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

Spring Bean的生命周期再完善

BeanDefinition

那BeanDefinition是什么? BeanDefinition是一個接口,我們進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 的定義信息可以包含許多配置信息,包括構造函數(shù)參數(shù),屬性值和特定于容器的信息,例如初始化方法,靜態(tài)工廠方法名稱等。子 bean 定義可以從父 bean 定義繼承配置數(shù)據(jù)。子 bean 的定義信息可以覆蓋某些值,或者可以根據(jù)需要添加其他值。使用父 bean 和子 bean 的定義可以節(jié)省很多輸入(實際上,這是一種模板的設計形式)。

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

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

lazyInit是否是懶加載。

這些都是描述Spring Bean的信息,我們可以類比到Java中的類,每個類都會有class屬性,我們在配置類或者xml中的配置Bean的元信息,也被映射到這里。供IOC容器將Bean加入時使用。所以我們可以為對Spring Bean的生命周期的理解打一個補丁:

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

我們可以打斷點來驗證一下:

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

Bean 加入IOC容器的幾種方式

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

啟動時加入

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

注解形式

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

運行時加入

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

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

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

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

從spring容器中動態(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 容器動態(tài)注冊bean實現(xiàn)方式的詳細內(nèi)容,更多關于Spring IOC 容器動態(tài)注冊bean的資料請關注腳本之家其它相關文章!

相關文章

  • Java fastjson2 解析JSON用法詳解

    Java fastjson2 解析JSON用法詳解

    Fastjson2是Fastjson的升級版,提供了更好的性能和擴展性,它支持多種方式解析JSON數(shù)據(jù),包括將JSON字符串轉(zhuǎn)換為Java對象、嵌套的JSON對象和數(shù)組,以及轉(zhuǎn)換成Map或List,本文介紹Java fastjson2 解析JSON用法,感興趣的朋友一起看看吧
    2025-02-02
  • Java的MyBatis框架中實現(xiàn)多表連接查詢和查詢結果分頁

    Java的MyBatis框架中實現(xiàn)多表連接查詢和查詢結果分頁

    這篇文章主要介紹了Java的MyBatis框架中實現(xiàn)多表連接查詢和查詢結果分頁,借助MyBatis框架中帶有的動態(tài)SQL查詢功能可以比普通SQL查詢做到更多,需要的朋友可以參考下
    2016-04-04
  • Java抽象的本質(zhì)解析

    Java抽象的本質(zhì)解析

    對于面向?qū)ο缶幊虂碚f,抽象是它的一大特征之一,在 Java 中可以通過兩種形式來體現(xiàn)OOP的抽象:接口和抽象類,下面這篇文章主要給大家介紹了關于Java基礎抽象的相關資料,需要的朋友可以參考下
    2022-03-03
  • Maven?pom.xml文件獲取當前時間戳方式

    Maven?pom.xml文件獲取當前時間戳方式

    這篇文章主要介紹了Maven?pom.xml文件獲取當前時間戳方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring Boot + Kotlin整合MyBatis的方法教程

    Spring Boot + Kotlin整合MyBatis的方法教程

    前幾天由于工作需要,便開始學習了kotlin,java基礎扎實學起來也還算比較快,對于kotlin這個編程語言自然是比java有趣一些,下面這篇文章主要給大家介紹了關于Spring Boot + Kotlin整合MyBatis的方法教程,需要的朋友可以參考下。
    2018-01-01
  • Java 利用枚舉實現(xiàn)接口進行統(tǒng)一管理

    Java 利用枚舉實現(xiàn)接口進行統(tǒng)一管理

    這篇文章主要介紹了Java 利用枚舉實現(xiàn)接口進行統(tǒng)一管理,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java的Character類詳解

    Java的Character類詳解

    在實際開發(fā)過程中,我們經(jīng)常會遇到需要使用對象,而不是內(nèi)置數(shù)據(jù)類型的情況。為了解決這個問題,Java語言為內(nèi)置數(shù)據(jù)類型char提供了包裝類Character類。本文詳細介紹了Java的Character類,感興趣的同學可以參考閱讀
    2023-04-04
  • Java 中synchronize函數(shù)的實例詳解

    Java 中synchronize函數(shù)的實例詳解

    這篇文章主要介紹了Java 中synchronize函數(shù)的實例詳解的相關資料,希望通過本文能幫助到大家理解使用synchronize函數(shù)的使用方法,需要的朋友可以參考下
    2017-09-09
  • springboot(thymeleaf)中th:field和th:value的區(qū)別及說明

    springboot(thymeleaf)中th:field和th:value的區(qū)別及說明

    這篇文章主要介紹了springboot(thymeleaf)中th:field和th:value的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • JAVA裝飾者模式(從現(xiàn)實生活角度理解代碼原理)

    JAVA裝飾者模式(從現(xiàn)實生活角度理解代碼原理)

    裝飾者模式可以動態(tài)地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更為靈活。這篇文章主要介紹了JAVA裝飾者模式的相關資料,需要的朋友可以參考下
    2016-12-12

最新評論

盐津县| 万山特区| 左权县| 关岭| 龙岩市| 万源市| 新巴尔虎右旗| 韶山市| 眉山市| 株洲县| 博白县| 平远县| 大埔县| 寻乌县| 曲水县| 荣成市| 吉木萨尔县| 新巴尔虎右旗| 阜新市| 拜城县| 安图县| 周口市| 纳雍县| 上饶市| 湟中县| 漯河市| 洛隆县| 交口县| 德清县| 通山县| 常宁市| 南召县| 株洲市| 榕江县| 武汉市| 阳西县| 洪江市| 姜堰市| 定西市| 高阳县| 资源县|