1. 程式人生 > >Spring IOC容器概述-筆記

Spring IOC容器概述-筆記

Spring實現依賴注入的Java底層技術是Java反射技術。

ICO:Spring容器的核心,AOP、宣告式事務等功能都基於此產生。
ICO不夠開門見山,所以後期由Martin Fowler用DI,依賴注入的概念代替了IoC,讓呼叫類對某一介面實現類的依賴由第三方(容器或者協作類)注入,從而移除呼叫類對某一介面實現類的依賴。
注入方式可以劃分為三種類型:建構函式注入、屬性注入和介面注入
Spring支援前兩種注入方式。

介面注入方式需要額外宣告一個介面,增加了類的數目,並且其效果同屬性注入並無區別,所以不提倡採用介面注入的方法。
Spring是這樣的一個容器,通過配置檔案或註解描述類和類之間的依賴關係,自動完成類的初始化和依賴注入工作。

Java允許使用者借用Class相關的元資訊物件間接呼叫Class的屬性,構造器和方法,就是所謂的反射。

invoke(Object object, Object param)第一個引數是操作目標類例項,第二個物件是目標方法的入參。

Class沒有public 的構造方法。Class物件是在裝載類時由JVM通過呼叫類裝載器中的defineClass()方法自動創造的。

Java反射

在java.reflect包中定義了三個最主要的反射類:
1.Constructor:類的構造器反射類,通過Class#getConstructor()方法可以獲得類的所有建構函式反射物件陣列。通過該類的newInstance(Object[] initargs)可以建立一個物件的例項,相當於new,JDK 5.0之後演化成了newInstance(Object…initargs),使用起來更加方便。
2.Method:類方法的反射類,通過Class#getDeclaredMethods()方法可以獲得類的所有方法反射類的陣列Method[]。該類的invoker(Object obj, Object[] args)可以呼叫這個方法,obj是目標物件,args是入參。
3.Field:類的成員變數的反射類,通過Class#getDeclaredFields()方法可以獲取類的成員變數的反射物件陣列。
Java的反射體系保證了可以通過程式化的方式訪問目標類中的所有元素。private和protected的成員變數和方法在JVM安全機制允許的情況下也可以通過反射進行呼叫。
JDK所提供的訪問資源的類並不能很好地滿足各種底層資源的訪問需求。Spring設計了一個Resource介面,為應用提供了更強的訪問底層資源的能力。
其主要方法:

boolean exists():判斷資源是否存在
boolean isOpen():判斷資源是否開啟

URL getURL() throws IOException:在支援的情況下返回底層資源的URL物件
File getFile() throws IOException:在支援的情況下返回底層資源的檔案物件
InputStream getInputStream() throws IOException:返回資源對應的輸入流
注意:Spring的Resource介面及其實現類可以在脫離Spring框架的情況下使用,它比通過JDK訪問資源的API更好用,更強大。

Spring可以在不顯式使用Resource實現類的情況下,僅通過資源地址的識別符號就可以載入相應的資源。同時支援Ant風格帶萬用字元的資源地址。
如:classpath: file: http:// ftp:// 無字首。
classpath*:可以載入所有打包JAR包及類路徑下具有特定名稱的資源。
Ant風格的三種萬用字元:?檔名任意一個字元 檔名任意字元 *

匹配多層路徑
PathMatchingResourcePatternResolver可以用於載入帶Ant風格的資源路徑

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resources[] =resolver.getResources("classpath*:com/baobaotao/**/*.xml");

Spring通過配置檔案描述Bean及Bean之間的依賴關係,利用Java預研的反射功能例項化Bean並建立Bean之間的依賴關係。
Spring IOC容器不僅完成了這些功能,還提供了Bean例項快取,生命週期管理,Bean例項代理,事件釋出,資源裝載等高階服務。
Bean工廠是Spring框架最核心的介面,提供了高階IOC的配置機制。使管理不同型別的Java物件成為可能。
應用上下文(ApplicationContext)建立在BeanFactory智商,提供了更多面嚮應用的功能,提供了國際化支援和框架事件體系,更易於建立實際應用。
傳統類工廠建立一個或者幾個類的例項,而BeanFactory是類的通用工廠,可以建立並管理各種類的物件。被其建立和管理的各種POJO被稱為Bean。所有可以被Spring容器例項化並管理的Java類都可以成為Bean。
ApplicationContext的主要實現類是ClassPathXmlApplicationContext和ListableBeanFactory介面,在此之上還通過多個其他介面擴充套件了BeanFactory的功能。

ConfigurableApplicationContext擴充套件於ApplicationContext,在原有的start/stop方法基礎上增加了refresh()和close(),在應用上下文關閉的情況下呼叫refresh()即可啟動應用上下文,在已經啟動的狀態下,呼叫refresh()則清除快取並重新裝載配置資訊,呼叫close()可以關閉應用上下文。
如果配置檔案放在類路徑下,則使用者可以優先使用ClassPathXmlApplicationContext實現類:

ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/context/beans.xml");

對於ClassPathXMlApplicationContext來說,路徑等同於classpath:com/baobaotao/context/beans.xml

如果配置檔案放置在檔案系統路徑下,則可以優先考慮使用FileSystemXmlApplicationContext實現類:
ApplicationContext ctx = new FileSystemApplicationContext(“com/baobaotao/context/beans.xml”);
對於FileSystemApplicationContext來說,路徑等同於file:com/baobaotao/context/bean.xml

在獲取了ApplicationContext之後,就可以像BeanFactory一樣呼叫getBean(beanName)的方法返回Bean了。
BeanFactory在使用Bean時才會初始化,而ApplicationContext在初始化應用上下文時就例項化所有單例項的Bean。所以ApplicationContext的初始化要稍微慢一些。

Spring所支援的基於類註解的配置方式,主要功能來自於JavaConfig的子專案,該專案已經升級為Spring核心框架的一部分。
標註位@Configuration註解的POJO即可提供Spring所需的Bean配置資訊。

使用如下語句便可以通過ApplicationContext的方式載入Beans.class中定義的Bean定義並呼叫其例項方法初始化Bean,啟動容器並裝配Bean。
ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class);
Car car =ctx.getBean(“car”,Car.class);

WebApplicationContext類體系結構
專門為web應用準備,允許從相對於Web根目錄的路徑中裝載配置檔案完成初始化工作。整個Web應用上下文物件將作為屬性放置到ServletContext中,一邊Web應用環境可以訪問Spring應用上下文。Spring利用WebApplicationContextUtils的getWebApplicationContext(ServletContext sc)方法,從中載入WebApplicationContext例項。

作用域:
非web環境Bean作用域:
singleton,prototype
web環境:
singleton,prototype,reuqest,session,global session

WebApplicationContext以ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE為鍵放置在ServletContext的屬性列表中。

Spring的Web容器:servletContext和Web應用上下文WebApplicationContext之間的互訪:
servletContext->WebApplicationContext: getAttribute(WebApplicaiton.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)
WebApplicationContext->servletContext:getServletContext()

WebApplicationContext初始化同BeanFactory和ApplicationContext有所區別,需要ServletContext例項,必須在擁有Web容器的前提下才能完成啟動工作。
Spring提供了用於啟動WebApplication的Servlet和Web容器監聽器:

org.springframework.web.context.ContextLoaderServlet
org.springframework.web.context.ContextLoaderListener

Bean的生命週期包括了從Spring容器著手開始初始化Bean開始到最終Bean的銷燬,這其中用了大致三類方法:
1. Bean自身方法:建構函式,Setter設定屬性。
2. Bean級生命週期介面
3. 容器生命週期介面方法:InstantiationAwareBeanPostProcessor和BeanPostProcessor兩個介面。後處理器,獨立於Bean。

Spring容器可以呼叫多個後處理器。
通過的init-method和destroy-method屬性配置方式為Bean指定初始化和銷燬的方法,採用這種方式對Bean生命週期的控制效果和通過實現InitializingBean,DisposableBean介面所達到的效果是完全相同的。前者可以使Bean不需要同特定的Spring框架介面繫結,達到了解耦的目的。Spring 2.1中還添加了一個InitDestroyAnnotationBeanPostProcessor,該Bean後處理將對標註了@PostConstruct,@PreDestroy註解的Bean進行處理,在Bean初始化和銷燬後執行相應的操作。

BeanPostProcessor介面不要求Bean去繼承它,可以完全像外掛一樣註冊到Spring容器中,為容器提供額外的功能。Spring容器充分的利用BeanPostProcessor對Bean進行加工處理,對於一般的應用而言,我們也不大會需要使用這個介面。Spring擴充套件外掛或者Spring子專案可以使用這些後處理器完成很多令人激動的功能。

ApplicationContext中Bean的宣告週期

如果Bean實現了org.springframework.context.ApplicationContextAware介面,會增加一個呼叫該介面方法

setApplicationContext()的步驟。
ApplicationContext和BeanFactory另一個最大的不同之處在於:前者可以利用Java反射機制自動識別出配置檔案中定義的

BeanPostProcessor,InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,並自動註冊到應用上下文中;後者需要

在程式碼中手工呼叫addBeanPostProcessor()方法進行註冊。所以在開發過程中我們普遍使用ApplicationContext而不是BeanFactroy


Spring框架三個最核心的介面:BeanFactory,ApplicationConetxt,WebApplicationContext。
框架通過Resource實現了和具體資源的解耦,不論其在何種儲存介質中,都可以通過相同的例項返回。
ResourceLoader通過策略模式,可以通過傳入資源地址的資訊,自動選擇適合的底層資源實現類,為上層對資源的引用提供了極大的便利。