<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
IOC 容器可以分為兩個階段 : 容器啟動階段和 Bean 範例化階段。
Spring 的 IoC 容器在實現的時候, 充分運用了這兩個階段的不同特點, 在每個階段都加入了相應的容器擴充套件點, 支援開發者根據具體場景的需要, 新增自定義的擴充套件邏輯.
容器啟動, 首先要載入設定後設資料 ( Configuration MetaData ).
容器使用工具類 BeanDefinitionReader 對載入的設定後設資料進行解析和分析, 並將分析後的資訊組裝為相應的 Bean 定義物件 BeanDefinition, 最後把這些儲存了 bean 定義必要資訊的 BeanDefinition, 註冊到相應的 BeanDefinitionRegistry, 這樣容器啟動工作就完成了. ( 將 XML 資訊對映到 BeanDefinition 物件上 )
BeanDefinition 物件中儲存的屬性很多,如下 :
BeanDefinitionRegister 介面用來註冊 BeanDefinition. 該介面的預設實現類為 DefaultListableBeanFactory. 在該實現類中, 有一個成員屬性定義如下 :
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, bean>(64);
BeanDefinition 就是被儲存到這個 map 中的, key 為 beanName, value 為 BeanDefinition 物件.
當呼叫者通過容器的 getBean() 方法明確地想要獲取某個物件, 或者因依賴關係, 容器需要隱式地呼叫 getBean() 方法時, 就會觸發容器的第二階段.
該階段, 容器會首先檢查所請求的物件之前是否已經初始化. 如果沒有, 則會根據註冊的 BeanDefinition 的資訊, 範例化這個物件 , 併為其注入依賴. 如果該物件實現了某些回撥介面, 也會根據回撥介面的要求來裝配它. 當該物件裝配完畢之後, 容器會立即將其返回給請求方去使用.
Bean 建立的步驟和普通物件的建立步驟不同, 普通的物件在建立時, 由類載入器找到 xxx.class 檔案, 然後建立 xxx 物件即可. Spring 中 bean 的建立多了一步, 先是由 類載入器找到 xxx.class 檔案, 然後將其解析組裝為 BeanDefinition 物件, 然後 Spring 根據 BeanDefinition 資訊來建立物件.
可以看到, Spring 在範例化物件時, 脫離了設定後設資料中的資訊, 而是使用的 BeanDefinition 中的資訊, 這就意味著我們可以修改 BeanDefinition, 從而改變 Spring 生成的物件的屬性, 甚至是修改最後生成的物件所屬的類.
Spring 提供了一種叫做 BeanFactoryPostProcessor 的容器擴充套件機制. 該機制允許開發者在容器範例化相應 Bean 物件之前, 對註冊到容器的 BeanDefinition 的資訊做出修改. 即在容器的第一階段的最後進行一些自定義操作. 比如修改其中 bean 定義的某些屬性, 為 bean 定義增加其他資訊等.
Spring 中自帶的 BeanFactoryPostProcessor 介面的實現:
同時也支援開發者通過實現 BeanFactoryPostProcessor 介面自定義擴充套件.
PropertyPlaceholderConfigurer 允許開發者在 XML 組態檔中使用預留位置, 並將這些預留位置所代表的資源單獨設定到簡單的 properties 檔案中來載入.
比如將資料庫的連線資訊儲存在 properties 中.
<context:property-placeholder location="classpath:dbconfig.properties" /> <bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
基本流程 :
PropertyOverrideConfigurer 允許你對容器中設定的任何你想處理的 bean 定義的 property 資訊進行覆蓋替換.
PropertyOverrideConfigurer 的 properties 檔案中的設定項, 可以覆蓋掉原來 XML 中的 bean 定義的 property 資訊.
此案例使用註解的方式來設定後設資料.
現在有兩個類, 一個是 User 類, 一個是 Good 類, User 類歸 Spring 管理, 而 Good 類並不歸 Spring 管理. 類的定義如下 :
@Data @AllArgsConstructor @Accessors(chain = true) @Component //被 Spring 掃描 public class User { private int id; private String name; public User(){ System.out.println("呼叫了 user 的無引數的構造方法"); } } @Data @AllArgsConstructor @Accessors(chain = true) public class Good { private int id; private String name; public Good(){ System.out.println("呼叫了 good 的無引數的構造方法"); } }
AppConfig 類進行註解的掃描.
@ComponentScan(value = {"it.com"}) public class AppConfig { }
Test 類用來測試 :
public static void main(String[] args){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); User user = (User) context.getBean("user"); Good good = (Good) context.getBean("good"); }
執行測試類, 結果如下 :
User 類設定了被 Spring 掃描, 所以可以獲取到 user 物件, 而 Good 類沒有設定被掃描, 所以無法獲取 good 物件, 而報錯.
現在我們要做的就是, 讓沒有被 Spring 管理的 Good 類, 也能從 Spring 容器中獲取到它的範例. 實現上述目的的思路就是, 對容器啟動的第一階段生成的 User 類的 BeanDefinition 類做修改.
建立自定義的 BeanFactoryPostProcessor 如下 :
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 通過 Spring 中 bean 的名字獲取到指定的 bean GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("user"); // 輸出 beanDefinition 的資訊 System.out.println(beanDefinition.getBeanClass()); System.out.println(beanDefinition.getFactoryBeanName()); // 然後進行狸貓換太子,將 User 類對應的 BeanDefinition 物件的 beanClass 屬性替換掉 beanDefinition.setBeanClass(Good.class); } }
然後再次執行測試類, 結果如下 :
可以看到,雖然表面上是通過 getBean("user") 來獲取 user 物件,但是實際呼叫的確實 Good 物件的構造方法,返回的是 good 物件. 但 Good 並沒有讓 Spring 掃描. 這個例子就展示瞭如何通過 BeanFactoryPostProcessor 機制插手容器的啟動
以上就是IOC 容器啟動和Bean範例化兩個階段詳解的詳細內容,更多關於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