亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

(spring-第5回【IoC基礎篇】)spring容器從加載配置文件到實例化bean的內部工作機制

2019-11-14 15:04:08
字體:
來源:轉載
供稿:網友

前面講過,sPRing的生命周期為:實例化前奏-->實例化-->實例化后期-->初始化前期-->初始化-->初始化后期-->bean的具體調用-->銷毀前-->銷毀。那么,從裝配xml屬性到實例化bean的內部機制是怎樣的,沒有細說,今天我們來一起刨根問底。

還是老風格,以具體例子先入為主。下面是一個再簡單不過的spring框架的栗子。(XML,有。Bean,有。Spring容器,有。main函數,有。麻雀雖小,但是夠了。)

這是XML,簡單易懂,嘎嘣脆:

1 。。。。。。2 3 <bean id="car" class="com.mesopotamia.test1.Car" 4          p:brand="寶馬X5"5          p:maxSpeed="200"/>6 </beans>

這是Bean,要個子有個子,要西一翁有西一翁:

代碼001

1
public class Car { 2 private String name; 3 private String brand; 4 private double maxSpeed; 5 public double getMaxSpeed() { 6 return maxSpeed; 7 } 8 public void setMaxSpeed(double maxSpeed) { 9 this.maxSpeed = maxSpeed;10 }11 12 13 private Log log=LogFactory.getLog(Car.class);14 15 public Car(){16 name="寶馬";17 log.info("調用了Car的構造函數,實例化了Car,并把Car的name屬性設為:"+name);18 }19 public String getName() {20 return name;21 }22 public void setName(String name) {23 this.name = name;24 }25 public String getBrand() {26 return brand;27 }28 public void setBrand(String brand) {29 this.brand = brand;30 }31 32 33 public String toString(){34 return "名字"+name+" 型號"+" 速度:"+maxSpeed;35 }36 37 38 }

下面是啟動函數,精悍!干練:

代碼002

1
public class Main {2 private static Log log=LogFactory.getLog(Main.class);3 4 public static void main(String args[]){5 applicationContext ctx = new ClassPathXmlApplicationContext("com/mesopotamia/test1/*.xml");6 Car car1 = ctx.getBean("car",Car.class);7 log.info(car1.toString());8 }

但是我要講的重點是main函數跑起來后的日志:

代碼003

1
2015-11-16 20:19:04,318 INFO [main] (AbstractApplicationContext.java:456) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1ff5ea7: startup date [Mon Nov 16 20:19:04 CST 2015]; root of context hierarchy2 2015-11-16 20:19:04,371 INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions from file [C:/MySoftware/workspace/springtest/WebRoot/WEB-INF/classes/com/mesopotamia/test1/beans.xml]3 2015-11-16 20:19:04,482 INFO [main] (DefaultListableBeanFactory.java:555) - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6e293a: defining beans [car]; root of factory hierarchy4 2015-11-16 20:19:04,483 INFO [main] (Car.java:22) - 調用了Car的構造函數,實例化了Car,并把Car的name屬性設為:寶馬5 2015-11-16 20:19:04,533 INFO [main] (Main.java:15) - 名字寶馬 型號 速度:200.0

一開始就加載了AbstractApplicationContext里的方法,那么這個方法做了什么?實際上,第一行是由AbstractApplicationContext的refresh()方法打印出的,容器一啟動就要加載這個方法,讓我們來揭開refresh()的面紗吧。

首先,這個AbstractApplicationContext必須是ClassPathXmlApplicationContext的父類,否則代碼002的第5行怎么一跑起來會跑到AbstractApplicationContext里面的方法里去?孩子被打,當然是去叫爹咯。

在MyEclipse里,我們按住ctrl鍵,點擊ClassPathXmlApplicationContext一路點下去你就發現其中的繼承關系(姑且用—>表示子類指向被繼承的父類):

ClassPathXmlApplicationContext —> AbstractXmlApplicationContext —>AbstractRefreshableConfigApplicationContext —>AbstractRefreshableApplicationContext—>AbstractApplicationContext。

我們進入AbstractApplicationContext,看到refresh()方法的廬山真面目:

 1 public void refresh() throws BeansException, IllegalStateException { 2         synchronized (this.startupShutdownMonitor) { 3             // Prepare this context for refreshing. 4             prepareRefresh(); 5  6             // Tell the subclass to refresh the internal bean factory. 7             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8  9             // Prepare the bean factory for use in this context.10             prepareBeanFactory(beanFactory);11 12             try {13                 // Allows post-processing of the bean factory in context subclasses.14                 postProcessBeanFactory(beanFactory);15 16                 // Invoke factory processors registered as beans in the context.17                 invokeBeanFactoryPostProcessors(beanFactory);18 19                 // Register bean processors that intercept bean creation.20                 registerBeanPostProcessors(beanFactory);21 22                 // Initialize message source for this context.23                 initMessageSource();24 25                 // Initialize event multicaster for this context.26                 initApplicationEventMulticaster();27 28                 // Initialize other special beans in specific context subclasses.29                 onRefresh();30 31                 // Check for listener beans and register them.32                 registerListeners();33 34                 // Instantiate all remaining (non-lazy-init) singletons.35                 finishBeanFactoryInitialization(beanFactory);36 37                 // Last step: publish corresponding event.38                 finishRefresh();39             }40 41             catch (BeansException ex) {42                 // Destroy already created singletons to avoid dangling resources.43                 destroyBeans();44 45                 // Reset 'active' flag.46                 cancelRefresh(ex);47 48                 // Propagate exception to caller.49                 throw ex;50             }51         }52     }

人生若只如初見,看到這如此美麗的代碼是否驚呆了天真爛漫的你?OK,我知道你英語沒我好,我就大概講一下這refresh()里面都干了些什么,這些步驟實際上就是實例化之前的一系列美麗動作:

第9行:準備bean factory  (BeanFactory是spring框架的基礎設施)

第16行:調用被注冊為bean的BeanFactoryPostProcessors(工廠后處理器) ?。üS后處理器負責對實例化之前未成形的bean進行加工處理)

第19行:注冊BeanPostProcessors(Bean后處理器)來阻擋bean的創建?! 。▽嵗蟮腷ean需要用這個后處理器來進一步加工)

第22行:初始化消息源(國際化信息資源)。 ?。▏H化很容易理解吧?比如微信可以切換中英文版本等等,后面會獨列篇幅講解)

第25行:初始化應用上下文事件廣播器。 ?。╯pring有一套完善的事件發布和監聽機制,事件廣播器負責把事件通知給監聽器,監聽器來執行事件。后面會獨列篇幅講解)。

第28行:初始化其他特殊的bean。

第31行:檢查是否有監聽器然后注冊監聽器(監聽器就跟bean一樣,需要放在注冊表中。后面會獨列篇幅講解)。

第34行:初始化所有單實例的bean(懶模式bean除外),單實例的bean初始化后把bean的引用放在spring容器的緩存中,調用者使用的是同一個額引用,任何一個調用者對bean的修改都會影響其他調用者。懶模式是指,spring容器啟動時不會初始化,而在需要用到該bean時才初始化。XML<bean>標簽中的lazy-init屬性就是設置懶模式或者勤快模式的,false是勤快模式,true是懶模式。

第37行:創建上下文刷新事件,發布廣播器?! ?事件機制后面會獨列篇幅講解)

 

上面這些就是bean實例化前后的細枝末節了。那么上面的什么工廠后處理器,bean后處理器被調用后又是怎樣處理的呢?

下面我們來細化一下創建一個完整的bean的作業流程:

整體是下面這樣的:

簡單點:

讀取XML,轉化并加工成BeanDefinition,實例化BeanDefinition。

具體點:

ResourceLoader加載XML配置信息后,由BeanDefinitionReader讀取配置信息文件,把每個<bean>解析成BeanDefinition對象保存在注冊表中。容器首先掃描注冊表取出工廠后處理器,對注冊表中的BeanDefinition進行加工處理。Spring容器接著從注冊表中取出加工過的BeanDefinition開始著手bean實例化的事情。實例化時,首先由BeanWapper對bean進行封裝,配置屬性。最后利用注冊表中的Bean后處理器裝飾打扮,裝配出一個準備就緒的Bean來。(注冊表就類似于一個Map<K,V>,把所有的bean,不管是業務bean,還是spring自己的bean,都放到注冊表里,用的時候取出來)。

 

再具體點:

  1. ResourceLoader加載XML配置信息后,由BeanDefinitionReader讀取配置信息文件,把每個<bean>解析成BeanDefinition對象保存在BeanDefinitionRegistry注冊表中。這時的BeanDefinition可能只是個半成品,因為某些XML屬性配置里會有占位符變量,這些變量此時不會被解析出來,需要繼續優化,比如下面這樣:
    1    <bean id="simpleBean" class="com.spring.ch04.SimplePostProcessor">  2    <property name="connectionString" value="${simpleBean.connectionString}"/>  3    <property name="passWord" value="${simpleBean.password}"/>  4    <property name="username" value="${simpleBean.username}"/>  5      6    </bean>  

     

  2. 因為有1的情況出現,所以容器首先掃描注冊表取出工廠后處理器,對注冊表中的BeanDefinition進行加工處理,把占位符替換成真正的值,產生成品的BeanDefinition。
  3. 通過反射機制掃描BeanDefinitionRegistry所有屬性編輯器的bean類,并把這些bean放到spring容器的屬性編輯器注冊表(PropertyEditorRegistry)中。(Spring的屬性編輯器負責將配置文件中的文本配置值轉換為Bean屬性的配置值,這個后面會獨辟章節來講)。
  4. Spring容器從BeanDefinitionRegistry中取出加工后的BeanDefinition,并調用InstantiationStrategy著手對bean的實例化工作。(這里的實例化只是相當于new了一個新對象一樣,也就是說,只是跑一個構造函數,不會具體的為屬性設置值,當然如果構造函數里寫了設置值的語句,那么也可以賦值。比如一開始的那個例子,實例化時在構造函數里就給Car的name屬性附上了"寶馬"的名字)。
  5. 實例化的過程中,spring容器使用BeanWrapper對bean進行封裝,BeanWrapper結合BeanDefinition和屬性編輯器注冊表中的屬性編輯器完成bean的屬性設置工作。
  6. 最后調用Bean后處理器對bean 作最后的潤色。

 

話音到此戛然而止。洗洗睡吧。

 

  知者不惑,仁者不憂,勇者不懼。

               ----子曰

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲奶大毛多的老太婆| 日韩免费在线看| 亚洲成人免费网站| 日韩欧美国产骚| 欧美亚洲国产视频| 久久天堂av综合合色| 日韩中文字幕视频在线| 欧美劲爆第一页| 国产精品入口福利| 日韩精品在线影院| 久久精品成人欧美大片古装| 亚洲一品av免费观看| 51视频国产精品一区二区| 亚洲日本中文字幕免费在线不卡| 91精品国产综合久久久久久久久| 欧美日韩在线视频一区二区| 91沈先生在线观看| 国产精品444| 亚洲男人天堂古典| 国产精品久久久久久久久久久久久久| 欧美成人黑人xx视频免费观看| 亚洲第一男人av| 久久精品视频一| 精品国产999| 8x拔播拔播x8国产精品| 7777精品久久久久久| 欧美激情在线狂野欧美精品| 国产成人在线一区| 日韩视频免费在线| 亚洲欧美在线磁力| 日本中文字幕久久看| 国产一区二区三区日韩欧美| 久久久精品影院| 久热精品视频在线观看一区| 美女视频久久黄| 日韩精品视频免费专区在线播放| 国产精品极品美女在线观看免费| 久久福利视频网| 国产精品日韩久久久久| 国产精品久久久久久超碰| 国产欧美精品久久久| 国产成人午夜视频网址| 久热精品视频在线观看一区| 91视频88av| 久久精品国产亚洲一区二区| 精品国产福利在线| 久久精品小视频| 国产精品女人网站| 亚洲自拍欧美色图| 亚洲高清久久久久久| 国产精品永久免费| 懂色av中文一区二区三区天美| 国产精品xxxxx| 亚洲精品av在线| 精品久久久久久久久久久久久久| 国产精品999999| 久久久天堂国产精品女人| 国产精品久久久久7777婷婷| 欧美成人性色生活仑片| 欧美放荡办公室videos4k| 亚洲最大中文字幕| 欧美性猛交xxxx久久久| 精品国产网站地址| 日韩av网址在线观看| 国产成人啪精品视频免费网| 亚洲精品久久久久久久久| 日韩精品视频中文在线观看| 国产精品久久精品| 中文字幕在线观看日韩| 日韩不卡中文字幕| 欧美一级高清免费| 91在线无精精品一区二区| 91久久久精品| 欧美日韩国产黄| xxx成人少妇69| 国产精品午夜视频| 久久亚洲一区二区三区四区五区高| 欧美激情成人在线视频| 国产精品久久久久久久久久免费| 国产精品网红直播| 国产精品 欧美在线| 欧美日韩国产在线播放| 欧美激情精品久久久久久黑人| 欧美激情中文字幕乱码免费| 国产精品电影久久久久电影网| 久久99久久99精品中文字幕| 日韩精品视频在线观看免费| 亚洲精品久久7777777| 久久久精品日本| 性欧美xxxx视频在线观看| 在线观看国产精品日韩av| 国产成人鲁鲁免费视频a| xxx欧美精品| 日本欧美国产在线| 91av成人在线| 欧洲精品久久久| 日韩在线观看免费| 成人看片人aa| 国产精品观看在线亚洲人成网| 色妞色视频一区二区三区四区| 午夜免费久久久久| 欧美亚洲在线视频| 国产日韩视频在线观看| 欧美午夜片欧美片在线观看| 日本高清久久天堂| 欧美精品免费在线观看| 欧美日韩精品二区| 亚洲电影在线看| 日韩激情在线视频| 亚洲国产精品嫩草影院久久| 亚洲女人被黑人巨大进入| 亚洲欧美日韩一区二区在线| 美女扒开尿口让男人操亚洲视频网站| 日韩电影中文字幕在线观看| 亚洲午夜精品久久久久久性色| 国产综合香蕉五月婷在线| 91麻豆国产语对白在线观看| 日本午夜在线亚洲.国产| 久久国产精品偷| 欧美精品在线免费| 国产精品中文字幕在线观看| 精品五月天久久| 成人在线免费观看视视频| 久久久国产精品一区| 国语自产在线不卡| 欧美国产高跟鞋裸体秀xxxhd| 亚洲最大福利视频网| 国产男人精品视频| 国产精品一区二区久久| 97在线看福利| 一区二区三区视频观看| 欧美劲爆第一页| 欧美性xxxxx极品| 日韩av最新在线观看| 国产成人精品电影| 国产一区红桃视频| 欧美成人一区二区三区电影| 亚洲精品中文字幕av| 免费av在线一区| 欧美激情a在线| 亚洲无限av看| 91色视频在线导航| 成人在线精品视频| 成人午夜两性视频| 亚洲人成77777在线观看网| 亚洲人成自拍网站| 97国产精品人人爽人人做| 国产精品小说在线| 久久韩剧网电视剧| 日韩福利视频在线观看| 日韩av日韩在线观看| 日韩精品在线免费观看| 久青草国产97香蕉在线视频| 国产一区二区三区中文| 亚洲国产高清自拍| 国产精品v片在线观看不卡| 一本大道亚洲视频| 欧美激情精品久久久久久变态| 亚洲精品资源美女情侣酒店| 亚洲黄色成人网| 国外成人在线视频| 亚洲精品www久久久久久广东| 亚洲欧美日韩视频一区| 91精品久久久久久久久中文字幕|