Spring是分層的Java SE/EE應用一站式的輕量級開源框架,以IoC(Inverse of Control)和AOP(Aspect Oriented Programming)爲內核,提供了展示層Spring MVC和持久層Spring JDBC以及業務層事務管理等衆多的企業級應用技術,此外,Spring整合了開源世界裏衆多的第三方框架和類庫。
Spring的體系結構:
Spring整個框架按其所屬功能可劃分爲5個主要模塊:數據訪問和集成、Web及遠程操做、測試框架、AOP和IoC。
IoC:Spring的核心模塊實現了IoC的功能,它將類和類之間的依賴從代碼中脫離出來,用配置的方式進行依賴關係描述,由IoC容器負責依賴類之間的建立、拼接、管理、獲取等工做。BeanFactory接口是Spring框架的核心接口,它實現了容器許多核心的功能。Context模塊構建於核心模塊之上,擴展了BeanFactory的功能,添加了i18n國際化、Bean生命週期控制、框架事件體系、資源加載透明化等多項功能。此外,該模塊還提供了許多企業級服務的支持。ApplicationContext是Context模塊的核心接口。表達式語言模塊是統一表達式語言的一個擴展,該表達式語言用於查詢和管理運行期的對象,支持設置或獲取對象屬性,調用對象方法、操做數組、集合等。還提供了邏輯表達式運算、變量定義等功能。使用它能夠方便地經過表達式串和Spring IoC容器進行交互。
AOP模塊:AOP是進行橫切邏輯編程的思想,開拓了人們考慮問題的思路。在AOP模塊裏,Spring提供了知足AOP Alliance規範的實現,此外,還整合了AspectJ這種AOP語言級的框架。Java 5.0引入java.lang.instrument,容許在JVM啓動時啓用一個代理類,經過該代理類在運行期修改類的字節碼,改變一個類的功能,實現AOP的功能。
數據訪問和集成:Spring站在DAO的抽象層面,創建了一套DAO層統一的異常體系,同時將各類訪問數據的檢查型異常轉換成非檢查型異常,爲整個各類持久層框架提供基礎。其次,Spring經過模版化技術對各類數據訪問技術進行了薄層的封裝,將模式化的代碼隱藏起來,使數據訪問的程序獲得了大幅簡化。
Web及遠程調用:該模塊創建在ApplicationContext模塊之上,提供了Web應用的各類工具類,若經過Listener或Servlet初始化Spring容器,將Spring容器註冊到Web容器中。其次,該模塊還提供了多項面向Web的功能。此外,Spring還能夠整合Struts、WebWork、Tapestry Web等MVC框架。
Spring註解:
在ApplicationContext文件中,使用Spring的<context:component-scan base-package="">掃描指定類包下的全部類,這樣在類中定的Spring註解才能產生做用。
@Repository:定義一個DAO Bean
@Autowired:將Spring容器中的Bean注入進來
@Service:將一個類標註爲一個服務層的Bean
@ContextConfiguration:指定Spring的配置容器
@Controller:將一個類標註爲Spring MVC的Controller
@RequestMapping(value="/index.html"):負責處理一個xxx.html請求
IoC
DI(Dependency Injection):讓調用類的某一接口實現類的依賴關係由第三方(容器或協做類)注入,以移出調用類對某一接口實現類的的依賴。
從注入方法上來看,主要能夠劃分爲3種類型:構造函數注入、屬性注入和接口注入。Spring支持構造函數注入和屬性注入。
構造函數注入:在構造函數注入中,咱們經過調用類的構造函數,將接口實現類經過構造函數變量傳入。
屬性注入:屬性注入能夠有選擇地經過Setter方法完成調用類所需依賴的注入。
接口注入:將調用累全部依賴注入的方法抽取到一個接口中,調用類經過實現該接口提供相應的注入方法。
java的反射機制
Java語言容許經過程序化的方式間接對Class的對象實例操做,Class文件由類裝載器裝載後,在JVM中將造成一份描述Class結構的元信息對象,經過該元信息對象能夠獲知Class的結構信息:構造函數、屬性和方法等。Java容許用戶藉由這個Class相關的元信息對象間接調用Class對象的功能.
例:
public Class Car{
private String brand;
private String color;
private int maxSpeed;
public Car(){}
public Car(String brand,String color,int maxSpeed){
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public void introduce(){
System.out.println("brand"+brand+",color"+color+",+maxSpeed"+maxSpeed);
}
...
}
import java.lang.reflect.Construcor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest{
public static Car initByDefaultConst() throws Throwable{
//經過類加載器獲取Car類對象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass(Car):
//獲取類的默認構造器對象並經過它實例化Car
Constructor cons = clazz.getDeclardConstructor((Class[])null);
Car car = (Car)cons.newInstance():
//經過反射方法設置屬性
Method setBrand = clazz.getMethod("setBrand",String.class);
setBrand.invoke(car,"WCA72");
Method setColor = clazz.getMethod("setColor ",String.class);
setColor .invoke(car,"black");
Method setMaxSpeed = clazz.getMethod("setMaxSpeed ",int.class);
setMaxSpeed .invoke(car,200);
return car;
}
public static void main(String[] args) throws Throwable{
Car car = initByDefaultConst();
car.introduce();
}
}
類裝載器ClassLoader
工做機制:
類裝載器就是尋找類的字節碼文件並構造出類在JVM內部表示的對象組件。在Java中,類裝載器裝入JVM中,要通過如下步驟:
1.裝載:查找和導入Class文件
2.連接:執行校驗、準備和解析步驟,其中解析步驟是能夠選擇的:
校驗:檢查載入Class文件數據的正確性
準備:給類的靜態變量分配存儲空間
解析:將符號引用轉成直接引用
3.初始化:對類的靜態變量、靜態代碼塊執行初始化工做
類加載器工做由ClassLoader及其子類負責,ClassLoader是一個重要的Java運行時系統組件,它負責在運行時查找和裝入Class字節碼文件。JVM在運行時會產生三個ClassLoadre:根裝載器、ExtClassLoader和AppClassLoader。根裝載器不是ClassLoader的子類,負責裝載JRE的核心類庫。ExtClassLoader和AppClassLoader都是ClassLoader的子類。其中,EctClassLoader負責裝載JRE擴展目錄ext中的JAR類包,AppClassLoader負責裝載Classpath路徑下的類包。
JVM裝載類時使用「全盤負責委託機制」,「全盤負責」是指當一個ClassLoader裝載一個類時,除非顯式地使用另外一個ClassLoader,該類所依賴及引用的類也由這個ClassLoader載入:「委託機制」是指先委託父裝載器尋找目標類,只有在找不到的狀況下才從本身的類路徑中查找並裝載目標類。
ClassLoader的重要方法:
Class loadClass(String name):name參數指定類裝載器須要裝載類的名字,必須使用全限定類名。該方法有一個重載方法loadClass(String name,boolean resolve),resolve參數告訴類裝載器是否須要解析該類。在初始化類以前,應考慮進行類解析的工做,但並非全部的類都須要解析,若JVM值需知道該類是否存在或找出該類的超類,那麼就不須要進行解析。
Class defineClass(String name,byte[] b,int off,int len):將類文件的字節數組轉換成JVM內部的java.lang.Class對象。字節數組能夠從本地文件系統、遠程網絡獲取。name爲字節數組對應的全限定類名。
Class findSystemClass(String name):從本地文件系統載入Class文件,若本地文件系統更不存在該Class文件,將拋出ClassNotFoundException異常。
Class findLoadedClass():調用該方法來查看ClassLoader是否已裝入某個類。若已裝入,則返回java.lang.Class對象,不然返回null。
ClassLoader getParent():獲取類裝載器的父裝載器。
反射對象類在java.reflect包中定義,下面是最主要的三個反射類:
Constructor:類的構造函數反射類,經過Class#getContructors()方法能夠得到類的全部構造函數反射對象數組。在JDK 5.0中,還能夠經過getContructor(Class parameterTypes)獲取擁有特定入參的構造函數反射對象。Constructor的一個主要方法是newInstance(Object[] initargs),經過該方法能夠建立一個對象類的實例,至關於new關鍵字。
Method:類方法的反射類,經過Class#getDeclaredMehtods()方法能夠獲取類的全部方法反射類對象數組Method[]。在 JDK 5.0中能夠經過getDeclaredMehtods(String name,Class parameterTypes)獲取特定簽名的方法,name爲方法名;Class爲方法入參類型列表。Method最主要的方法是invoke(Object obj,Object[] args),obj表示操做的目標對象,args爲方法入參。
Method還有不少用於獲取類方法更多信息的方法:
Class getReturnType():獲取方法的返回值類型
Class[] getParameterTypes():獲取方法的入參類型數組
Class[] getExceptionTypes():獲取方法的一場類型數組
Annotationp[][] getParamerterAnnotations():獲取方法的註解信息
Field:類的成員變量的反射類,經過Class#getDeclaredFields()方法能夠獲取類的成員變量反射對象數組,經過Class#getDeclaredFields(String name)則可獲取某個特定名稱的成員變量反射對象。Field類最主要的方法是set(Object obj,Object value),obj表示操做目標評對象,經過value爲目標對象的成員變量設置值。若成員變爲爲基礎類型,用戶可使用Field類中提供的帶類型名的值設置方法。
經過反射機制能夠調用私有變量和私有方法。但在訪問private、protected成員變量和方法時必須經過setAccessible(boolean acess)方法取消java語言檢查,不然拋出IllegalAccessException。若JVM的安全管理器設置了相應的安全機制,調用該方法將拋出SecurityException。
Spring設計了一個Resource接口,它爲應用提供了更強的訪問底層資源的能力。該接口擁有對應不一樣資源類型的實現類。Resource接口的主要方法:
boolean exists():資源是否存在
boolean isOpen():資源是否打開
URL getURL() throws IOException:若底層資源能夠表示成URL,該方法返回對應的URL對象
File getFile() throws IOException:若底層資源對應一個文件,該方法返回對應的File對象
InputStream getInputStream() throws IOException:返回資源對應的輸入流
Spring框架使用Resource裝載各類資源,Resource的具體實現類以下:
ByteArrayResource:二進制數組表示的資源,二進制數組資源能夠在內存中經過程序構造
ClassPathResource:類路徑下的資源,資源以相對於類路徑的方式表示
FileSystemResource:文件系統資源,資源以文件系統路徑的方式表示
InputStreamResource:對應一個InputStream的資源
ServletContextResource:爲訪問web容器上下文中的資源而設計的類,負責以相對於Web應用根目錄的路徑加載資源,它支持已流和URL的方式訪問,在WAR解包的狀況下,也能夠經過File的方式訪問,還能夠直接從JAR包中訪問資源。
UrlResource:封裝了java.net.URL,它使用戶可以訪問任何能夠經過URL表示的資源。
對資源進行編碼:
EncodedResource encRes = new EncodedResource(res,"UTF-8");
資源類型的地址前綴
地址前綴 示例
classpath classpath:com/beans.xml
對應資源類型:從類路徑中加載資源,classpath:和classpath:/是等價的,都是至關於類的跟路徑。資源文件能夠在標準的文件系統中,也能夠在jar或zip的類包中
file: file:/com/beans.xml
對應資源類型:使用UrlResource從文件系統目錄中裝載資源,可採用絕對或相對路徑
http:// http://www.beans.xml
對應資源類型:使用UrlResource從Web服務器中裝載資源
ftp:// ftp://www.beans.xml
對應資源類型:使用UrlResource從FTP服務器中裝載資源
沒有前綴 com/beans.xml
對應資源類型:根據ApplicationContext具體實現類採用對應的類型的Resource
Ant風格資源地址支持3種匹配符:
?:匹配文件名中的一個字符
*:匹配文件名中任意字符
**:匹配多層路徑
Spring定義一套資源加載的接口,並提供了實現類。ResourceLoader接口僅有一個getResource(String location)的方法,能夠根據一個資源地址加載文件資源。不過這個文件資源僅支持帶資源類型前綴的表達式,不支持Ant風格的資源路徑表達式。ResourcePatternResolver擴展了ResourceLoader接口,定義了一個新的接口方法:getResources(String locationPattern),該方法支持帶資源類型前綴及Ant風格的資源路徑的表達式。PathMatchingResourcePatternResolver是Spring提供了標準實現類。
Spring爲BeanFactory提供了多種實現,最經常使用的XmlBeanFactory。
BeanFactory最主要的方法就是getBean(String beanName),該方法從容器中返回特定該名稱的Bean。BeanFactory的其餘接口:
ListableBeanFactory:該接口定義了訪問容器中Bean基本信息的若干方法
HierarchicalBeanFactory:父子級聯IoC容器的接口,子容器能夠經過接口方法訪問父容器。
ConfigurableBeanFactory:加強IoC容器的可定製性,它定義了設置類裝載其、屬性編輯器、容器初始化後置處理器等方法
AutowireCapableBeanFactory:定義了將容器中的Bean按某種規則進行自動裝配的方法
SingletonBeanRegistry:定義了容許在運行期間向容器註冊單實例Bean的方法
BeanDefinitionRegistry:Spring配置文件中每個<bean>節點元素在Spring容器裏都經過一個BeanDefinition對象表示,他描述了Bean的配置信息。而BeanDefinition Registry接口提供了向容器手工註冊BeanDefinition對象的方法。
ApplicationContext的主要實現類是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默認從類路徑加載配置文件,後者默認從文件系統中裝載配置文件。ApplicationContext繼承了HierarchicalBeanFactory和ListableBeanFactory接口。
ApplicationEventPublisher:讓容器擁有發佈應用上下文事件的功能,包括容器啓動事件、關閉事件等。實現了ApplicationListener事件監聽接口的Bean能夠接受到容器事件,並對事件進行響應處理。在ApplicationContext抽象實現類AbstractApplicationContext中,咱們能夠發現存在一個ApplicationEventMulticaster,它負責保存全部監聽器,以便在容器產生上下文事件時通知這些事件監聽者。
MessageSource:爲應用提供il18n國際化消息訪問功能。
ResourcePatternResolver:全部ApplicationContext實現類都實現了相似於PathMatchingResourcePatternResolver功能,能夠經過帶前綴的Ant風格的資源文件路徑裝載Spring的配置文件。
LifeCycle:該接口提供了start()和stop()兩個方法,主要用於控制異步處理過程。在具體使用時,ApplicationContext及具體的Bean都必須同時實現該接口,ApplicationContext會將start/stop的信息傳遞給容器中全部實現了該接口的Bean,已達到管理和控制JMX、任務調度等目的。
ConfigurableApplicationContext擴展與ApplicationContext,它新增了refresh()和close(),讓ApplicationContext具備啓動、刷新和關閉應用上下文的能力。在應用上下文關閉的狀況下調用refresh()便可啓動應用上下文,在已經啓動的狀態下,調用refresh()則清理緩存並從新裝載配置信息,而調用close()則可關閉應用上下文。
ApplicationContext和BeanFactory的重大區別:BeanFactory在初始化容器時,並未實例化Bean,直到第一次訪問某個Bean時才實例目標Bean;而ApplicationContext則在初始化應用上下文時就實例化全部單實例的Bean。因次,ApplicationContext的初始化事件會比BeanFactory稍長,但以後的調用沒有第一次懲罰的問題。
WebApplicationContext是專門爲Web應用準備的,它容許從相對於Web根目錄的路徑中裝載配置文件完成初始化工做。從WebApplicationContext中能夠得到ServletContext的引用,整個Web應用上下文對象將做爲屬性放置到ServletContext中,以便Web應用程序能夠訪問Srping應用上下文。Spring專門爲次提供一個工具類WebApplicationContextUtils,經過該類的getWebApplicationContext(ServletContext sc)方法,既能夠從ServletContext中獲取WebApplicationContext是實例。在WebApplicationContext中還爲Bean添加了三個新的做用域:request做用域、session做用域和global session做用域。而在爲Web應用環境下,Bean只有singleton和prototype兩種做用域。
WebApplicationContext定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文啓動時,WebApplicationContext實例即以此爲鍵放置在ServletContext的屬性列表中。
ConfigurableApplicationContext容許經過配置的方式實例化WebApplicationContext。
setServletContext(ServletContext servletContext):爲Spring設置Web應用上下文,以便二者整合
setConfigLocations(String[] configLocations):設置Spring配置文件地址,通常狀況下,配置文件地址是相對於Web根目錄的地址。
WebApplicationContext的初始化方式和BeanFactory、ApplicationContext有所區別。WebApplicationContext秀奧ServletContext實例,也就是說它必須在擁有Web容器的前提下才能完成啓動的工做。
Spring分別提供了用於啓動WebApplicationContext的Servlet的Web容器監聽器:
org.springframework.web.context.ContextLoaderServlet、org.springframework.web.context.ContextLoaderListener二者的內部都實現了啓動WebApplicationContext實例的邏輯,咱們只要根據Web容器的具體狀況選擇兩隻之一,並在web.xml中完成配置就能夠了。
因爲WebApplicationContext須要使用日誌功能,用戶能夠將Log4J的配置文件放置到類路徑的WEB-INF/classes下,這時Log4J引擎便可順利啓動。Spring爲啓動Log4J引擎提供了兩個相似於啓動WebApplicationContext的實現類:Log4jConfigServlet和Log4jConfigListener。
<context-param>
<param-name>contextConfigLocation</param-name>
<paramm-value>
/WEB-INF/xxx.xml,/WEB-INF/xxxx.xml
</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<paramm-value>
/WEB-INF/log4j.properties
</param-value>
</context-param>
<servlet>
<servlet-name>log4jConfigServlet</servlet-name>
<servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>springContextLoaderServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
經過HierarchicalBeanFactory接口,Spring的IoC容器能夠創建父子層級關聯的容器體系,子容器能夠訪問父容器中的Bean,但父容器不能訪問子容器的Bean。在容器內,Bean的id必須是惟一的,但子容器能夠擁有一個和父容器id相同的bean。父子容器層級體系加強了Spring容器架構的擴展性和靈活性。
Bean的生命週期:
1.當調用者經過getBean(beanName)向容器請求某一個Bean時,若容器註冊了org.springframework.beans.factory.InstantiationAwareBeanPostProcessor接口,在實例化Bean以前,將調用接口的postProcessBeforeInstantiation()方法。
2.根據配置狀況調用Bean構造函數或工廠方法實例化Bean
3.若容器註冊了InstantiationAwareBeanPostProcessor接口,在實例化Bean以後,調用該接口的postProcessAfterInstantiation()方法,可在這裏對已經實例化的對象進行相關操做。
4.若Bean配置了屬性信息,容器在這一步着手將配置值設置到Bean對應的屬性中,不過在設置每一個屬性以前先將調用InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues()方法。
5.調用Bean的屬性設置方法設置屬性值
6.若Bean實現了org.springframework.beans.factory.BeanNameAware接口,將調用setBeanName()接口方法,將配置文件中該Bean對應的名稱設置到Bean中。
7.若Bean實現了org.springframework.beans.factory.BeanFactoryAware接口,將調用setBeanFactory()接口方法,將BeanFactory容器實例設置到Bean中。
8.若BeanFactory裝配了org.springframework.beans.factory.config.BeanPostProcessor後處理器,將調用BeanPostProcessor的Object postProcessBeforeInitialization(Object bean,String beanName)接口方法對Bean進行加工操做。其中參數bean是當前正在處理的bean,而beanName的hi當前Bean的配置名,返回的對象爲加工處理後的Bean。BeanPostProcessor在Spring框架中佔有重要地位,爲容器提供對Bean進行後加工處理的切入點。
9.若Bean實現了InitializingBean的接口,將調用接口的afterPropertiesSet()方法
10.若在<bean>經過init-method屬性定義了初始化方法,將執行這個方法
11.BeanPostProcessor後處理器定義了兩個方法:其一是postProcessBeforeInitializatiopn()在第8步調用;其二是Object postProcessAfterInitialization(Object bean,String beanName)方法,這個方法在此時調用,容器在此得到對Bean進行加工處理的機會。
12.若在<bean>中指定Bean的做用範圍爲scope='prototype',將Bean返回給調用者,調用者負責調用者後續生命的管理,Spring再也不管理這個Bean的生命週期。若做用範圍設置爲scope='singleton',則將Bean放入到Spring IoC容器的緩存池中,並將Bean引用返回給調用者,Spring繼續對這些Bean進行後續的生命管理。
13.對於scope='singleton'的Bean,當容器關閉時,將觸發Spring對Bean的後續生命週期的管理工做,首先,若Bean實現了DisposableBean接口,則將調用接口的afterPropertiesSet()方法,能夠在次編寫釋放資源、記錄日誌等操做。
14.對於scope='singleton'的Bean,若經過<bean>的destroy-method屬性指定了Bean的銷燬方法,Spring將執行Bean這個方法,完成Bean資源的釋放等操做。
Bean的完整生命週期從Spring容器着手實例化Bean開始,知道最終銷燬Bean,這當中通過了許多關鍵點,每一個關鍵點都涉及特定的方法調用,能夠將這些方法大體劃分爲三類:
Bean自身的方法:若調用Bean構造函數實例化Bean,調用setter設置Bean的屬性值以及經過<bean>的init-method和destroy-method所制定的方法;
Bean級生命週期接口方法:如BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean,這些接口方法由Bean直接實現
容器級生命週期接口方法:後處理器接口通常不禁Bean自己實現,他們獨立於Bean,實現類以容器附加裝置的形式註冊到Spring容器中並經過接口反射爲Spring容器預先識別。Spring容器建立Bean時,這些後處理器都會發生做用,因此這些後處理器的影響是全局的。
ApplicationContext和BeanFactory的最大區別在於前者會利用Java的反射機制自動識別出配置文件中定義的BeanPostProcessor、IntantiationAwareBeanPostProcessor和BeanFactoryProcessor,並將他們註冊到應用上下文中,然後者須要在代碼中經過手工調用addBeanPostProcessor()方法進行註冊。html