IoC容器:的兩個核心功能是(1)完成了完成對象的建立和(2)bean依賴的管理注入......html
spring ioc 容器抽象的的幾個主要接口:java
Resource //資源文件的抽象,xml 、 properties ... BeanDefinition //bean的抽象定義 (bean的一些基本信息是不是 抽象、單例、懶加載、做用域...)基本信息 BeanDefinitionReader //不一樣的資源文件的bean的解析 BeanFactory //bean工廠的頂層抽象定義了幾個基礎的方法 getBean() contanisBean() .... ApplicationContext //應用程序上下文
1: Resource 接口spring
實現類:ClasspathResource、 解析classpath下的資源文件 URLResource、 解析url網絡資源文件namespace
FileSystemResource、 解析系統資源文件
Spring 提供了一些org.springframework.core.io.Resource接口的實現,能夠幫助咱們快速獲取Resource信息。
1. URLResource
封裝了java.net.URL:經過URL能夠得到的對象。
Resource resource = new UrlResource("file:/D:/java/src/bean.xml");
Resource resource = new UrlResource("http://127.0.0.1:8080/index.html");
Resource resource = new UrlResource(new URI("http://127.0.0.1:8080/index.html"));
2. FileSystemResource
處理java.io.File 本地資源文件
Resource resource = new FileSystemResource("file:C:\bean.xml");
3. ClassPathResource
獲取classpath下面的Resource
Resource resource = new ClassPathResource("com/resource/bean.xml");
Resource接口的一些經常使用方法:
2:BeanDefinition 接口 (描述一個bean對象的基本數據結構)數據庫
幾個重要的實現
BeanDefinitionParserDelegate //解析配置文件
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
parseBeanDefinitionElement()...多個重載方法實現bean的定義
public class ChildBeanDefinition extends AbstractBeanDefinition 、
public class RootBeanDefinition extends AbstractBeanDefinition 、
public class GenericBeanDefinition extends AbstractBeanDefinition 、
RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition均繼承了AbstractBeanDefiniton,
BeanDefinition對象是配置文件中<bean>元素標籤在容器中內部表示形式。
<bean>元素標籤擁有class、scope、lazy-init等配置屬性。
BeanDefinition則提供了相應的beanClass、scope、lazyInit屬性。
BeanDefinition和<bean>中的屬性是一一對應的。
其中RootBeanDefinition是最經常使用的實現類、它對應通常性的<bean>元素標籤,
GenericBeanDefinition是自2.5之後新加入的bean文件配置屬性定義類,是一站式服務類。
在配置文件中能夠定義父<bean>和子<bean>,父<bean>用RootBeanDefinition表示,而子<bean>用ChildBeanDefiniton表示,而
沒有父<bean>的<bean>就使用RootBeanDefinition表示。AbstractBeanDefinition對二者共同的類信息進行抽象。
Spring經過BeanDefinition將配置文件中的<bean>配置信息轉換爲容器的內部表示,並將這些BeanDefiniton註冊到BeanDefinitonRegistry中。
Spring容器的BeanDefinitionRegistry就像是Spring配置信息的內存數據庫,主要是以map的形式保存,後續操做直接從BeanDefinitionRegistry中讀取配置信息。
通常狀況下,BeanDefinition只在容器啓動時加載並解析,除非容器刷新或重啓,這些信息不會發生變化。
若是用戶有特殊的需求,也能夠經過編程的方式在運行期調整BeanDefinition的定義。
建立最終的BeanDefinition主要包括兩個步驟:
1)利用BeanDefinitionReader對配置信息Resource進行讀取,經過XML解析器解析配置信息的DOM對象,簡單地爲每一個<bean>生成對應的BeanDefinition對象。
可是這裏生成的BeanDefinition多是半成品,由於在配置文件中,咱們可能經過佔位符變量引用外部屬性文件的屬性,這些佔位符變量在這一步尚未被解析出來。
2)利用容器中註冊的BeanFactoryPostProcessor對半成品的BeanDefinition進行加工處理,
將以佔位符表示的配置解析爲最終的實際值,這樣半成品的BeanDefinition就爲成品的BeanDefinition。
3:BeanDefinitionReader 接口將配置信息轉換程BeanDefinition編程
BeanDefinitionReader將外部資源對象描述的bean定義統一轉化爲統一的內部數據結構BeanDefinition。
主要實現類:
XmlBeanDefinitionReader、用來讀取xml描述配置的bean對象。
PropertiesBeanDefinitionReader、用來解析 ×.properties文件描述配置的bean對象。
最後都會 registerBeanDefinitions(...) 註冊解析到的bean對象到map
4:BeanFactory 接口 (bean的工廠)緩存
主要方法
protected Object doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException { //bean name處理,去除FactoryBean前綴等 final String beanName = transformedBeanName(name); Object bean = null; //先從singleton緩存中查看是否已經實例化過該Bean,根據是否有緩存分爲兩個分支分別處理 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 分支一,若緩存中獲取到了而且該BeanDefinition信息代表該bean是singleton的,直接將獲取到的緩存Bean //(有多是半成品)交給getObjectForBeanInstance處理 //調用getObjectForBeanInstance處理 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else { // 分支二:沒有緩存,則須要從頭實例化該bean // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName);} // 檢查BeanDefinition是否在當前工廠或父工廠 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (args != null) { // 父工廠getBean return parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } //將bean加入「正在建立」的集合,完成後會remove,對應afterSingletonCreation/afterPrototypeCreation方法 if (!typeCheckOnly) { markBeanAsCreated(beanName); } final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 解決依賴關係,將依賴的bean提早實例化 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (int i = 0; i < dependsOn.length; i++) { String dependsOnBean = dependsOn[i]; getBean(dependsOnBean); registerDependentBean(dependsOnBean, beanName); } } // 這裏又須要根據bean的類型分爲三種狀況:singleton、prototype、request/session if (mbd.isSingleton()) { //經過自定義ObjectFactory實例化Bean,此結果多是半成品(是FactoryBean等) sharedInstance = getSingleton(beanName, new ObjectFactory() { public Object getObject() throws BeansException { try { //真正實例化裝配的邏輯在createBean方法中 return createBean(beanName, mbd, args); } catch (BeansException ex) { //顯式地刪除實例從單緩存:它可能已經把那裏
//熱切的建立過程,容許循環引用的決議。
//刪除任何bean,獲得一個臨時bean的引用。 destroySingleton(beanName); throw ex; } } }); //上一步半成品的Bean交給getObjectForBeanInstance方法處理 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); //真正實例化裝配的邏輯在createBean方法中 prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } //上一步半成品的Bean交給getObjectForBeanInstance方法處理 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { //request、session 的bean String scopeName = mbd.getScope(); final Scope scope = (Scope) this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory() { public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { //真正實例化裝配的邏輯在createBean方法中 return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); //上一步半成品的Bean交給getObjectForBeanInstance方法處理 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; " + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return bean; }
建立bean的步驟:
檢查Bean緩存,已經有緩存的Bean對象(有多是半成品)則交給getObjectForBeanInstance方法處理、
不然先根據Bean的生命週期類型分別實例化,每種狀況大體都分兩步,
第一步都交給createBean方法生產一個半成品的bean對象,
而後一樣是將半成品的bean交給getObjectForBeanInstance方法
ps:爲何createBean方法建立完的bean是半成品,該半成品交給getObjectForBeanInstance()方法後執行了什麼操做?
5:ApplicationContext 接口
public interface ApplicationContext extends EnvironmentCapable,網絡
ListableBeanFactory, //beanFactorysession
HierarchicalBeanFactory, //beanFactory
MessageSource, //處理消息的基本接口 能夠實現國際化....數據結構
ApplicationEventPublisher, //事件監聽ide
ResourcePatternResolver { //資源處理
主要實現類
ClasspathXmlApplicationContext,
FileSystemXmlApplicationContext,
WebApplicationContext Web上下文容器 (ServletContext)
//初始化過程 ClasspathXmlApplicationContext爲例
1.把配置xml文件轉換成resource。resource的轉換是先經過ResourcePatternResolver來解析可識別格式的配置文件的路徑
(如"classpath*:"等),若是沒有指定格式,默認會按照類路徑的資源來處理。
2.利用XmlBeanDefinitionReader完成對xml的解析,將xml Resource裏定義的bean對象轉換成統一的BeanDefinition。
3.將BeanDefinition註冊到BeanFactory,完成對BeanFactory的初始化。BeanFactory裏將會維護一個BeanDefinition的Map。
最後在調用 getBean的時候會執行
public void refresh() throws BeansException, IllegalStateException {
...
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //建立BeanFactory
//會實例化一個XmlBeanDefinitionReader來解析Resource文件。
...
.... }太長了不翻譯了
參考文檔:
1:http://www.neversaydie.cc/spring-ioc-introduce/
其它參考文章稍後貼出...