一、概述
Spring是J2EE應(yīng)用程序框架,是輕量級的IoC(控制反轉(zhuǎn))和AOP(面向切面)容器框架,主要針對javaBean的生命周期進行管理。使用基本的JavaBean代替了傳統(tǒng)的EJB栓袖,降低了企業(yè)應(yīng)用開發(fā)的復(fù)雜性匣摘。借助依賴注入、AOP應(yīng)用裹刮、面向接口編程等特性音榜,降低了業(yè)務(wù)組件之間的耦合度,增強了系統(tǒng)的可擴展性必指。Spring是非侵入式的囊咏,應(yīng)用中的對象不依賴于Spring的特定類∷穑可以整合和兼容其他框架梅割,讓已有的技術(shù)和框架更加易用。
二葛家、框架結(jié)構(gòu)
Spring框架是一個分層架構(gòu)户辞,由七個模塊組成。Spring的各模塊構(gòu)建在核心容器之上癞谒,核心容器定義了創(chuàng)建底燎、配置和管理bean的方式。
-
Spring Core
提供了Spring框架的基本功能弹砚。核心容器的主要組件是BeanFactory双仍,是工廠模式的實現(xiàn)。BeanFactory使用IoC將應(yīng)用程序的配置和依賴性規(guī)范與實際的應(yīng)用程序代碼分離桌吃。
-
Spring Context
是一個配置文件朱沃,為Spring框架提供上下文信息。Spring上下文包括各種企業(yè)服務(wù)茅诱,如JNDI逗物、EJB、電子郵件瑟俭、國際化翎卓、校驗和調(diào)度等。
-
Spring AOP
通過配置管理特性摆寄,該模塊將面向方面的編程功能集成到了Spring框架中失暴。為基于Spring的應(yīng)用程序中的對象提供了事務(wù)管理服務(wù),將聲明性事務(wù)管理集成到應(yīng)用程序中微饥。
-
Spring DAO
提供了有意義的異常層次結(jié)構(gòu)锐帜,可用該結(jié)構(gòu)來管理異常處理和錯誤信息。異常層次結(jié)構(gòu)簡化了錯誤處理畜号,極大地降低了需要編寫的異常代碼量。
-
Spring ORM
Spring框架插入了若干ORM框架允瞧,從而提供了ORM的對象關(guān)系工具简软。所有這些框架都遵從Spring的通用事務(wù)和DAO異常層次結(jié)構(gòu)蛮拔。
-
Spring Web
Web上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于Web的應(yīng)用程序提供了上下文痹升。Web模塊還簡化了處理多部分請求以及將請求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?/p>
-
Spring MVC
SpringMVC框架是一個全功能的構(gòu)建Web應(yīng)用程序的MVC實現(xiàn)建炫。
三、核心組件
Spring框架的核心組件主要有三個:Bean組件疼蛾、Context組件肛跌、Core組件。
1察郁、Bean組件
Bean組件在Spring的org.springframework.beans包下衍慎,這個包下的所有類主要負責(zé)bean的定義、創(chuàng)建皮钠、以及對bean的解析稳捆。在實際使用中只需要關(guān)注bean的創(chuàng)建即可,bean的定義和bean的解析由框架完成麦轰。
- bean的創(chuàng)建使用工廠模式乔夯,頂層接口是BeanFactory,最終的實現(xiàn)類是DefaultListableBeanFactory款侵。BeanFactory有三個子接口:ListableBeanFactory末荐、HierarchicalBeanFactory、AutowireCapableBeanFactory新锈。這四個接口共同定義了bean的集合甲脏、bean之間的關(guān)系、以及bean的行為壕鹉。
- bean的定義主要由BeanDefinition描述剃幌,描述了配置文件中所定義的<bean>節(jié)點中的所有信息。當(dāng)Spring成功解析節(jié)點后晾浴,節(jié)點信息被轉(zhuǎn)化成BeanDefinition對象负乡,之后所有的操作都是針對該對象。
- bean的解析主要就是對Spring配置文件的解析脊凰。
2抖棘、Context組件
Context組件在Spring的org.springframework.context包下,提供一個運行時環(huán)境狸涌,用以保存各個對象的狀態(tài)切省。ApplicationContext是Context的頂級父類,標(biāo)識了一個應(yīng)用環(huán)境的基本信息帕胆。還繼承了五個接口朝捆,主要擴展Context的功能。
ApplicationContext主要有兩個子類:
- ConfigurableApplicationContext懒豹,表示該Context是可修改的芙盘,用戶在構(gòu)建Context時可以動態(tài)添加或修改已有的配置信息驯用。
- WebApplicationContext,表示是為web準(zhǔn)備的Context儒老,可以直接訪問ServletContext蝴乔。
ApplicationContext必須完成以下幾件事:
- 標(biāo)識一個應(yīng)用環(huán)境
- 利用BeanFactory創(chuàng)建Bean對象
- 保存對象關(guān)系表
- 能夠捕獲各種事件
3、Core組件
Core組件包含了很多關(guān)鍵類驮樊,其中一個重要部分就是定義了資源的訪問方式薇正。Resource接口封裝了各種可能的資源類型,對使用者屏蔽了文件類型的不同囚衔。Resource接口繼承了InputStreamSource接口挖腰,接口中的getInputStream方法返回InputStream類,所有的資源都可以通過這個類來獲取佳魔,也屏蔽了資源的提供者曙聂。ResourceLoader接口屏蔽了資源的加載者,只需要實現(xiàn)這個接口就可以加載所有類型的資源鞠鲜。Context把資源的加載宁脊、解析和描述工作委托給ResourcePatternResolver類來完成,由它整合在一起供其他組件使用贤姆。
四榆苞、原理
1、IoC
IoC是Spring的核心之一霞捡。傳統(tǒng)情況下坐漏,當(dāng)一個對象依賴于另一個對象時,需要通過new操作主動創(chuàng)建另一個對象的實例碧信,這樣的話赊琳,兩個對象之間就產(chǎn)生了耦合。通過IoC砰碴,一個對象依賴的其他對象會通過被動的方式傳遞進來躏筏,而不是自己創(chuàng)建或查找依賴對象。創(chuàng)建依賴對象實例的工作通常由Spring容器來完成呈枉,然后注入給依賴者趁尼,所以也被稱為DI(依賴注入)。
1.1 IoC容器
BeanFactory是IoC容器的核心接口猖辫,負責(zé)實例化酥泞、定位、配置應(yīng)用程序中的對象及建立這些對象間的依賴啃憎。XMLBeanFactory實現(xiàn)BeanFactory接口芝囤,通過獲取xml配置文件數(shù)據(jù),組成應(yīng)用對象及對象間的依賴關(guān)系。
- BeanFactoryPostProcessor凡人,在構(gòu)建BeanFactory時調(diào)用
- BeanPostProcessor名党,在構(gòu)建Bean對象時調(diào)用
- InitializingBean,在Bean實例創(chuàng)建時調(diào)用
- DisposableBean挠轴,在Bean實例銷毀時調(diào)用
- FactoryBean,用來創(chuàng)建Bean實例的Bean
1.2 注入方法
可以通過三種方法進行注入:set方法耳幢、構(gòu)造函數(shù)岸晦、接口。
set方法注入
可以為屬性提供set方法睛藻。在配置文件中添加bean標(biāo)簽启上,屬性class的值為對象實現(xiàn)類的完整路徑。添加property標(biāo)簽店印,屬性name的值與對象類中對應(yīng)的屬性名稱一致冈在,屬性value的值就是給對象類中對應(yīng)的屬性注入的值。
實現(xiàn)類:
public class User {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username= username;
}
}
配置文件:
<bean id="userAction" class="com.spring.action.User" >
<property name="username" value="admin"></property>
</bean>
也可以為對象提供set方法按摘。在配置文件中添加對引用對象的bean聲明包券,屬性ref的值是所要引用的對象。這樣炫贤,框架就會將引用對象注入到對象類中溅固。
實現(xiàn)類:
public class UserAction {
private UserService userservice;
public void setUserService(UserService userservice) {
this.userservice = userservice;
}
}
配置文件:
<bean id="userService" class="com.spring.service.UserService"></bean>
<bean id="userAction" class="com.spring.action.UserAction" >
<property name="userservice" ref="userService"></property>
</bean>
構(gòu)造方法注入
直接通過構(gòu)造函數(shù),將要依賴的屬性或?qū)ο笞鳛閰?shù)傳遞給構(gòu)造函數(shù)兰珍。
實現(xiàn)類:
public class UserAction {
private String username;
public UserAction(String username) {
this.username= username;
}
}
配置文件:
<bean id="userAction" class="com.spring.action.UserAction" >
<constructor-arg constructor-argvalue="admin"></constructor-arg>
</bean>
接口方法注入
并不常用侍郭,所以不做介紹。
1.3 自動裝配
修改Spring配置文件中bean標(biāo)簽的autowire屬性掠河,可以進行自動裝配亮元,簡化配置,提高開發(fā)效率唠摹。自動裝配屬性有六個值爆捞,分別代表不同的含義:
-
byName
從Spring環(huán)境中獲取目標(biāo)對象時,目標(biāo)對象中的屬性會根據(jù)名稱在整個Spring環(huán)境中查找bean標(biāo)簽的id屬性值跃闹。如果有相同的嵌削,則獲取這個對象,實現(xiàn)關(guān)聯(lián)望艺。要保證id不能重復(fù)苛秕。
-
byType
從Spring環(huán)境中獲取目標(biāo)對象時,目標(biāo)對象中的屬性會根據(jù)名稱在整個Spring環(huán)境中查找bean標(biāo)簽的class屬性值找默。如果有相同的艇劫,則獲取這個對象,實現(xiàn)關(guān)聯(lián)惩激。當(dāng)存在多個相同類型的bean對象時店煞,會出錯蟹演。
-
constructor
使用構(gòu)造方法完成對象注入,也就是根據(jù)構(gòu)造方法的參數(shù)類型進行對象查找顷蟀,相對于采用byType方式酒请。
-
autodetect
如果對象沒有無參數(shù)的構(gòu)造方法,則自動選擇constructor的裝配方式進行構(gòu)造注入鸣个;如果對象含有無參數(shù)的構(gòu)造方法羞反,則自動選擇byType的裝配方式進行set注入。
-
default
默認采用上一級標(biāo)簽的自動裝配的值囤萤。
-
no
不進行自動裝配昼窗。
2、AOP
AOP是Spring的另一個核心涛舍。Spring通過AOP澄惊,允許分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級服務(wù)(如日志、事務(wù)富雅、權(quán)限等)掸驱,從而提高了內(nèi)聚性。
2.1 AOP與OOP
AOP即面向切面編程吹榴,與OOP面向?qū)ο缶幊滔噍o相成亭敢。OOP要求職責(zé)分離,不同的類完成不同的功能图筹,降低了代碼的復(fù)雜度帅刀,便于重用。但在職責(zé)分離的同時远剩,如果多個類需要進行相同操作時扣溺,需要在每個類中都加入這些內(nèi)容,增加了代碼的重復(fù)性瓜晤。如果將這些內(nèi)容單獨封裝在一個類中锥余,再通過每個類進行調(diào)用,會增加類之間的耦合度痢掠。AOP就是在程序運行時驱犹,動態(tài)地將這些內(nèi)容切入到類的指定方法、指定位置上足画。OOP中雄驹,基本單元是類;AOP中淹辞,基本單元是切面医舆。OOP橫向分成各個類,AOP縱向給對象加入特定代碼。
2.2 AOP術(shù)語
AOP中包含很多術(shù)語蔬将,理解這些術(shù)語才能全面的理解AOP的真正含義爷速。
-
切面(Aspect),橫切面的功能霞怀,用于抽象出類或接口
由Advice和Pointcut組成惫东,既包含了橫切面的定義,也包含了切入點的定義里烦≡渌猓可以使用@Aspect注解實現(xiàn)。
-
增強(Advice)胁黑,橫切面功能的具體實現(xiàn),對象的實例
由Aspect添加到特定Joinpoint的代碼州泊,
-
連接點(Joinpoint)丧蘸,程序運行期間的時間節(jié)點
在Spring AOP中,Joinpoint總是表現(xiàn)為方法執(zhí)行遥皂。
-
切入點(Pointcut)力喷,描述橫切面功能應(yīng)用的限制
使用Pointcut的目的就是提供一組規(guī)則來匹配Joinpoint,只為滿足條件的Joinpoint添加Advice代碼演训。
-
代理(Proxy)弟孟,織入Advice的結(jié)果類
Spring AOP默認使用JDK動態(tài)代理為接口實現(xiàn)代理。如果業(yè)務(wù)邏輯對象沒有實現(xiàn)接口样悟,則使用CGLIB代理拂募。Spring AOP建議基于接口編程,對接口進行AOP窟她,而不是基于類陈症。
-
目標(biāo)(Target),業(yè)務(wù)操作的實際對象震糖,織入Advice的目標(biāo)對象录肯,也被稱為被增強的對象
因為Spring AOP是通過運行時代理的方式實現(xiàn)Aspect的,所以目標(biāo)對象總是一個代理對象吊说。一個類被AOP織入Advice后论咏,會產(chǎn)生一個結(jié)果類,是包含原類和增強邏輯的代理類颁井。
-
織入(Weave)厅贪,將組件應(yīng)用到業(yè)務(wù)流程中的過程,將Aspect和其他對象關(guān)聯(lián)并創(chuàng)建目標(biāo)對象的過程
Spring采用動態(tài)代理織入蚤蔓,而AspectJ則采用編譯器和類裝載器織入卦溢。
2.3 用法
定義Aspect
當(dāng)使用注解@Aspect標(biāo)注一個Bean后,Spring框架會自動將其添加到Spring AOP中。要想將對象轉(zhuǎn)換成Bean单寂,還需要使用@Component之類的注解贬芥。如果一個類被@Aspect標(biāo)注,那么這個類就不能成為其他Aspect的目標(biāo)對象了宣决。
@Component
@Aspect
public class Test{
}
聲明Pointcut
Pointcut聲明由兩部分組成:一個pointcut表達式蘸劈,一個方法簽名。使用注解@Pointcut標(biāo)注pointcut表達式尊沸。
@Pointcut("execution(* com.service.UserService.*(..))")
private void dataAccessOperation() {}
該聲明描述的是:匹配com.service.UserService下的所有方法的執(zhí)行威沫。
pointcut表達式由指示器和操作參數(shù)組成。指示器有以下幾種:
- execution洼专,匹配joinpoint的執(zhí)行
- within棒掠,匹配特定類下的所有joinpoint的執(zhí)行
- this,匹配一個bean屁商,該bean是一個給定類型的實例
- target烟很,匹配一個目標(biāo)對象,該對象是一個給定類型的實例
- bean蜡镶,匹配指定bean下的所有方法
- args雾袱,匹配參數(shù)滿足要求的方法
- @annotation,匹配由指定注解所標(biāo)注的方法
聲明Advice
Advice通常是和Pointcut表達式關(guān)聯(lián)在一起使用的官还。
@Component
@Aspect
public class BeforeAspectTest {
// 定義一個Pointcut, 使用切點表達式函數(shù)來描述對哪些Joinpoint使用advise
@Pointcut("execution(* com.service.UserService.*(..))")
public void dataAccessOperation() {
}
}
@Component
@Aspect
public class AdviseDefine {
// 定義advise
@Before("com.aspect.PointcutDefine.dataAccessOperation()")
public void doBeforeAccessCheck(JoinPoint joinPoint) {
System.out.println("Before advise, method: " + joinPoint.getSignature().toShortString());
}
}
3芹橡、注解
注解Annotation是一種類似注釋的機制,在代碼中添加注解可以在之后的某個時間使用這些信息望伦。Java虛擬機不會對注解進行編譯林说,而是通過反射機制讀取注解中的信息。使用注解的主要目的是為了提高開發(fā)效率屡谐,不需要配置過多的xml文件述么,不必在配置文件中添加標(biāo)簽。
3.1 使用注解
需要在配置文件中增加命名空間和約束文件:
<beans ...
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
...
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd
">
3.2 配置基包
告訴框架哪些類使用注解:
<context:component-scan base-package="com.spring" />
3.3 注解種類
Spring框架自帶很多注解愕掏。
持久層注解@Repository
@Repository
public class UserDao{
// ......
}
等同于配置文件中的:
<bean id="userDao" class="com.spring.UserDao" />
服務(wù)層注解@Service
@Service(value="testService")
public classTestService {
@Resource //相當(dāng)于自動裝配
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
等同于配置文件中的:
<bean id="testService" class="com.spring.UserService" />
其中度秘,@Resource表示對象間的關(guān)系,默認采用byName方式進行裝配饵撑,如果找不到關(guān)聯(lián)對象剑梳,則采用byType方式裝配。
控制層注解@Controller
@Controller(value="ua")
@Scope(value="prototype")
public class UserAction {
@Resource
private UserService userService滑潘;
public UserService getUserService() {
return userService;
}
}
等同于配置文件中的:
<bean id="ua" class="com.spring.UserAction " />
Tips:以上三層中的組件關(guān)鍵字都可以使用@Component來代替垢乙。
從Spring環(huán)境中獲取Action對象
ServletContext application =request.getSession().getServletContext();
ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(application);
// 獲取控制層對象
UserAction useraction = (UserAction)ac.getBean("ua");
// 設(shè)置編碼
response.setContentType("text/html;charset=GBK");
PrintWriter out = response.getWriter();
// 分別打印三個層的對象
out.println("Action:" + userAction);
out.println("Service:" + userAction.getUserService());
out.println("Dao:" + userAction.getUserService().getUserDao());