<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
這周遇到了這樣一個需求,從第三方的資料庫中獲取值,只是一個簡單的分頁查詢,處理這種問題,我一般都是在組態檔中設定資料庫的地址等相關資訊,然後在Spring Configuration 註冊資料量連線池的bean,然後再將資料庫連線池給JdbcTemplate, 但是這種的缺陷是,假設填錯了資料庫地址和密碼,或者換了資料庫的地址和密碼,在組態檔裡面重啟之後,都需要重啟應用。
我想能不能動態的向Spring IOC容器中註冊和載入bean呢,專案在介面上填寫資料庫的地址、使用者名稱、密碼,儲存之後,將JdbcTemplate和另一個資料庫連線池載入到IOC容器中。答案是可以的,我經過一番搜尋寫出瞭如下程式碼:
@Component public class BeanDynamicRegister { private final ConfigurableApplicationContext configurableApplicationContext; public BeanDynamicRegister(ConfigurableApplicationContext configurableApplicationContext) { this.configurableApplicationContext = configurableApplicationContext; } /** * 此方法提供出去,供其他bean動態的向IOC容器中註冊bean。 * 代表使用構造器給bean賦值 * * @param beanName bean名 * @param clazz bean類 * @param args 用於向bean的建構函式中新增值 如果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) { // 將引數加入到建構函式中 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容器裡經過了幾步:
聯絡我們前面的文章《Spring Bean 的生命週期》,我們將Spring 的生命週期理解為“Spring 給我們提供的一些擴充套件介面,如果bean實現了這些這些介面,應用在啟動的過程中會回撥這些介面的方法。” , 這個理解並不完善,缺少了解析BeanDefinition這個階段。
那BeanDefinition是什麼? BeanDefinition是一個介面,我們進Spring 官網(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 的定義資訊可以包含許多設定資訊,包括建構函式引數,屬性值和特定於容器的資訊,例如初始化方法,靜態工廠方法名稱等。子 bean 定義可以從父 bean 定義繼承設定資料。子 bean 的定義資訊可以覆蓋某些值,或者可以根據需要新增其他值。使用父 bean 和子 bean 的定義可以節省很多輸入(實際上,這是一種模板的設計形式)。
這段說的可能有點抽象, 你點BeanDefinition進去,你就會發現有很多熟悉的面孔:
Bean的作用域: 單例,還是多例。
lazyInit是否是懶載入。
這些都是描述Spring Bean的資訊,我們可以類比到Java中的類,每個類都會有class屬性,我們在設定類或者xml中的設定Bean的元資訊,也被對映到這裡。供IOC容器將Bean加入時使用。所以我們可以為對Spring Bean的生命週期的理解打一個修補程式:
我們可以打斷點來驗證一下:
我們這裡再來總結一下一個Bean注入Spring IOC容器的幾種形式:
啟動時加入
註解形式
執行時加入
這三種最終都是通過BeanDefinitionRegistry來注入的,ImportBeanDefinitionRegistrar是一個介面,留給我們實現的方法如下:
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { }
BeanDefinitionRegistryPostProcessor也是一個介面,留給我們實現的方法如下:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
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 容器動態註冊bean實現方式的詳細內容,更多關於Spring IOC 容器動態註冊bean的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45