Spring 源碼學習 - ClassPathXmlApplicationContext

衆所周知,Spring以其強大而又靈活的IoC管理功能著稱。IoC本質上是通過依賴注入DI的方式實現組件之間的解耦。其實在DI模式下,一個關鍵性的角色是裝配器(assembler)。應用程序的組件A在引用別的組件B的時候不用通過new來創建,而是依賴一個第三方的裝配器創建好B,然後再通過setter或者constructor來注入給A,這樣A只管用B的接口,而不需要知道B的存在,從而實現了A與B的解耦。也實現了面向抽象(接口)編程。

Spring框架裏面誰來充當這個assembler的角色呢?是BeanFactory。Spring提供了品種繁多的BeanFactory,共用戶在不同場合下使用。我們通常更多的是使用它的子接口ApplicationContext。大致上分了三類:Java Application,Web Application 和 Portlet Application。

本文通過一個簡單的例子([url]http://svn.springbyexample.org/core/basic-dependency-injection/[/url])來看看ClassPathXmlApplicationContext的調用和執行順序圖(用MaintainJ生成的):

[img]http://dl.iteye.com/upload/attachment/0067/6260/08825bef-0faa-308f-9146-090846fbc648.png[/img]

上圖的init代表執行構造函數。上圖表達了下面這句話:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");

再看看類圖:

[img]http://dl.iteye.com/upload/attachment/0067/6262/23e28826-c3f9-32cb-9990-ed024647b8d0.png[/img]

再細緻的看下去,分解StandardEnvironment的構建過程(可以看出是解析各種屬性的過程):

[img]http://dl.iteye.com/upload/attachment/0067/6271/d72f5189-9247-3179-816b-71ff3c4d4da6.png[/img]

屬性都load好了,環境也構建好了,那麼Bean的實例在哪裏創建的呢?關鍵得看DefaultListableBeanFactory:

[img]http://dl.iteye.com/upload/attachment/0067/6275/3f2f55d9-8da9-3b20-a641-8494365431b8.png[/img]

這裏面關鍵是看registerSingleton函數,它負責把bean緩存到singletonObjects (private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();)

public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
addSingleton(beanName, singletonObject);
}
}

/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

從上面的邏輯上可以看出,同名的類是不能被緩存進去的,會拋出異常。
好了,後的程序想getBean的時候只需要從這個緩存中獲取就好了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章