本博中關(guān)于spring的文章:Spring
IOC和AOP原理,Spring事務(wù)原理探究,Spring配置文件屬性詳解,Spring中的代理模式
Spring提供了很多輕量級應(yīng)用開發(fā)實踐的工具集合,這些工具集以接口、抽象類、或工具類的形式存在于Spring中。通過使用這些工具集,可以實現(xiàn)應(yīng)用程序與各種開源技術(shù)及框架間的友好整合。比如有關(guān)jdbc封裝的數(shù)據(jù)訪問工具Spring JDBC,有關(guān)編寫單元測試的spring test包以及spring-mock,有關(guān)訪問動態(tài)腳本語言的Spring Script,另外還有發(fā)送郵件的工具Spring Mail、日程及任務(wù)處理工具Spring scheduling等。 可以這么說,大多數(shù)企業(yè)級應(yīng)用開發(fā)中經(jīng)常涉及到的一些通用的問題,都可以通過Spring提供的一些實用工具包輕松解決 依賴注入的三種方式:(1)接口注入(2)Construct注入(3)Setter注入
控制反轉(zhuǎn)(IoC)與依賴注入(DI)是同一個概念,引入IOC的目的:(1)脫開、降低類之間的耦合;(2)倡導(dǎo)面向接口編程、實施依賴倒換原則; (3)提高系統(tǒng)可插入、可測試、可修改等特性。 org.springframework.beans及org.springframework.context包是Spring IoC容器的基礎(chǔ)。BeanFactory提供的高級配置機制,使得管理任何性質(zhì)的對象成為可能。ApplicationContext是BeanFactory的擴展,功能得到了進(jìn)一步增強,比如更易與Spring AOP集成、消息資源處理(國際化處理)、事件傳遞及各種不同應(yīng)用層的context實現(xiàn)(如針對web應(yīng)用的WebApplicationContext)。 簡而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext則增加了更多支持企業(yè)核心內(nèi)容的功能。ApplicationContext完全由BeanFactory擴展而來,因而BeanFactory所具備的能力和行為也適用于ApplicationContext。 IoC容器負(fù)責(zé)容納bean,并對bean進(jìn)行管理。在Spring中,BeanFactory是IoC容器的核心接口。它的職責(zé)包括:實例化、定位、配置應(yīng)用程序中的對象及建立這些對象間的依賴。Spring為我們提供了許多易用的BeanFactory實現(xiàn),XmlBeanFactory就是最常用的一個。該實現(xiàn)將以XML方式描述組成應(yīng)用的對象以及對象間的依賴關(guān)系。XmlBeanFactory類將持有此XML配置元數(shù)據(jù),并用它來構(gòu)建一個完全可配置的系統(tǒng)或應(yīng)用。 實現(xiàn)化容器:
將XML配置文件分拆成多個部分是非常有用的。為了加載多個XML文件生成一個ApplicationContext實例,可以將文件路徑作為字符串?dāng)?shù)組傳給ApplicationContext構(gòu)造器。而bean factory將通過調(diào)用bean defintion reader從多個文件中讀取bean定義。
通常情況下,Spring團隊傾向于上述做法,因為這樣各個配置并不會查覺到它們與其他配置文件的組合。另外一種方法是使用一個或多個的<import/>元素來從另外一個或多個文件加載bean定義。所有的<import/>元素必須放在<bean/>元素之前以完成bean定義的導(dǎo)入。
讓我們看個例子:
<beans><import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans> 在上面的例子中,我們從3個外部文件:services.xml、messageSource.xml及themeSource.xml來加載bean定義。這里采用的都是相對路徑,因此,此例中的services.xml一定要與導(dǎo)入文件放在同一目錄或類路徑,而messageSource.xml和themeSource.xml的文件位置必須放在導(dǎo)入文件所在目錄下的resources目錄中。正如你所看到的那樣,開頭的斜杠‘/’實際上可忽略。因此不用斜杠‘/’可能會更好一點。
根據(jù)Spring XML配置文件的Schema(或DTD),被導(dǎo)入文件必須是完全有效的XML bean定義文件,且根節(jié)點必須為<beans/> 元素。
===============================================================上面已講到
BeanFactory它的職責(zé)包括:實例化、定位、配置應(yīng)用程序中的對象及建立這些對象間的依賴。
FactoryBean(通常情況下,bean無須自己實現(xiàn)工廠模式,Spring容器擔(dān)任工廠角色;但少數(shù)情況下,容器中的bean本身就是工廠,其作用是產(chǎn)生其它bean實例),作用是產(chǎn)生其他bean實例。通常情況下,這種bean沒有什么特別的要求,僅需要提供一個工廠方法,該方法用來返回其他bean實例。由工廠bean產(chǎn)生的其他bean實例,不再由Spring容器產(chǎn)生,因此與普通bean的配置不同,不再需要提供class元素。
ProxyFactoryBean用于創(chuàng)建代理(根據(jù)Advisor生成的Bean,也就是TargetBean的代理)
我們的Advisor,PointCut等等,其最終目的都是為了創(chuàng)建這個代理。
===============================================================下面將講到
AOP全名Aspect-Oriented Programming,中文直譯為面向切面(方面)編程,當(dāng)前已經(jīng)成為一種比較成熟的編程思想,可以用來很好的解決應(yīng)用系統(tǒng)中分布于各個模塊的交叉關(guān)注點問題。在輕量級的J2EE中應(yīng)用開發(fā)中,使用AOP來靈活處理一些具有橫切性質(zhì)的系統(tǒng)級服務(wù),如事務(wù)處理、安全檢查、緩存、對象池管理等,已經(jīng)成為一種非常適用的解決方案。 AOP中比較重要的概念有:Aspect、JoinPoint、PonitCut、Advice、Introduction、Weave、Target Object、Proxy Object等 引介(Introduction)是指給一個現(xiàn)有類添加方法或字段屬性,引介還可以在不改變現(xiàn)有類代碼的情況下,讓現(xiàn)有的Java類實現(xiàn)新的接口,或者為其指定一個父類從而實現(xiàn)多重繼承。相對于增強(Advice)可以動態(tài)改變程序的功能或流程來說,引介(Introduction)則用來改變一個類的靜態(tài)結(jié)構(gòu)。比如我們可以讓一個現(xiàn)有為實現(xiàn)java.lang.Cloneable接口,從而可以通過clone()方法復(fù)制這個類的實例。 攔截器是用來實現(xiàn)對連接點進(jìn)行攔截,從而在連接點前或后加入自定義的切面模塊功能。在大多數(shù)JAVA的AOP框架實現(xiàn)中,都是使用攔截器來實現(xiàn)字段訪問及方法調(diào)用的攔截(interception)。所用作用于同一個連接點的多個攔截器組成一個連接器鏈(interceptor chain),鏈接上的每個攔截器通常會調(diào)用下一個攔截器。Spring AOP及JBoos AOP實現(xiàn)都是采用攔截器來實現(xiàn)的。 面向?qū)ο缶幊蹋∣OP)解決問題的重點在于對具體領(lǐng)域模型的抽象,而面向切面編程(AOP)解決問題的關(guān)鍵則在于對關(guān)注點的抽象。也就是說,系統(tǒng)中對于一些需要分散在多個不相關(guān)的模塊中解決的共同問題,則交由AOP來解決;AOP能夠使用一種更好的方式來解決OOP不能很好解決的橫切關(guān)注點問題以及相關(guān)的設(shè)計難題來實現(xiàn)松散耦合。因此,面向方面編程 (AOP) 提供另外一種關(guān)于程序結(jié)構(gòu)的思維完善了OOP,是OOP的一種擴展技術(shù),彌補補了OOP的不足。
AOP概念詳解:注意以下實例<aop:開頭的AspectJ的概念,Spring沒有分的這么細(xì)。 — 方面(Aspect):一個關(guān)注點的模塊化,這個關(guān)注點實現(xiàn)可能另外橫切多個對象。事務(wù)管理是一個很好的橫切關(guān)注點例子。方面用Spring的Advisor或攔截器實現(xiàn), 然后可以通過@Aspect標(biāo)注或在applictionContext.xml中進(jìn)行配置: <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"> — 連接點(Joinpoint):程序執(zhí)行過程中的行為,如方法的調(diào)用或特定的異常被拋出,在代碼上有JoinPoint類和ProceedingJoinPoint類,如下所示,可以通過JoinPoint獲取很多參數(shù),JoinPoint一般用在Advice實現(xiàn)方法中作為參數(shù)傳入,ProceedingJoinPoint用于實現(xiàn)圍繞Advice的參數(shù)傳入。 通過下面JoinPoint的接口可以看出通過JoinPoint可以得到代理對象和Target對象。
— 切入點(Pointcut):指定一個Adivce將被引發(fā)的一系列連接點的集合。AOP框架必須允許開發(fā)者指定切入點,例如,使用正則表達(dá)式。 xml中配置: <aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> 或使用Annoation :@pointcut("execution * transfer(..)")并用一個返回值為void,方法體為空的方法來命名切入點如: private void anyOldTransfer(){} 之后就可以在Advice中引用,如: @AfterReturning(pointcut="anyOldTransfer()", returning="reVal")
關(guān)于PointCut中使用的execution的說明: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) modifiers-pattern:方法的操作權(quán)限 ret-type-pattern:返回值 declaring-type-pattern:方法所在的包 name-pattern:方法名 parm-pattern:參數(shù)名 throws-pattern:異常 記憶法則就是Java定義一個方法時的樣子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就可以了。 其中,除ret-type-pattern和name-pattern之外,其他都是可選的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值為任意類型;方法名任意;參數(shù)不作限制的所有方法。 常見的PointCut結(jié)構(gòu)圖:
— 通知(Advice):在特定的連接點,AOP框架執(zhí)行的動作。各種類型的通知包括“around”、“before”和“throws”通知。通知類型將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連接點的攔截器鏈。Advice中必須用到PointCut 在xml中配置,配置中的method為Aspect實現(xiàn)類中的方法名,使用pointcut自定義或pointcut-ref進(jìn)行引用已有pointcut <aop:before pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="authority" /> <aop:after pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> <aop:after-returning pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="log" /> <aop:around pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="processTx" /> <aop:after-throwing pointcut-ref="myPointcut" method="doRecovertyActions" throwing="ex" />
或使用Annoation: @Before("execution(* com.wicresoft.app.service.impl.*.*(..))") @AfterReturning(returning="rvt", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))") @AfterThrowing(throwing="ex", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))") @After("execution(* com.wicresoft.app.service.impl.*.*(..))") @Around("execution(* com.wicresoft.app.service.impl.*.*(..))") 注意
使用方法攔截器的around通知,需實現(xiàn)接口MethodInterceptor: public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable; } invoke()方法的MethodInvocation 參數(shù)暴露將被調(diào)用的方法、目標(biāo)連接點、AOP代理和傳遞給被調(diào)用方法的參數(shù)。 invoke()方法應(yīng)該返回調(diào)用的結(jié)果:連接點的返回值。 一個簡單的MethodInterceptor實現(xiàn)看起來如下:
注意MethodInvocation的proceed()方法的調(diào)用。這個調(diào)用會應(yīng)用到目標(biāo)連接點的攔截器鏈中的每一個攔截器。大部分?jǐn)r截器會調(diào)用這個方法,并返回它的返回值。但是, 一個MethodInterceptor,和任何around通知一樣,可以返回不同的值或者拋出一個異常,而不調(diào)用proceed方法。但是,沒有好的原因你要這么做。
Before通知:需實現(xiàn)MethodBeforeAdvice接口 public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable; } Throw通知,需實現(xiàn)ThrowsAdvice接口 After Returning通知須直線AfterReturningAdvice接口 public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable; }
— 引入(Introduction):添加方法或字段到被通知的類,引入新的接口到任何被通知的對象。例如,你可以使用一個引入使任何對象實現(xiàn)IsModified接口,來簡化緩存。使用introduction要有三個步驟(1)聲明新接口(2)創(chuàng)建自己的IntrouductionInterceptor通過Implements IntroductionInterceptor或extends DelegatingIntroductionInterceptor 并同時implements(1)中聲明的接口 (3)將新接口和自定義的IntroductionInterceptor配置到DefaultIntroductionAdvisor中,然后將前三者配置到ProxyFactoryBean中。
— 攔截器(Advisor )常用的有PointCutAdvisor和IntroudtionAdvisor。前者Advisor有PointCut和Advice組成,滿足Poincut(指定了哪些方法需要增強),則執(zhí)行相應(yīng)的Advice(定義了增強的功能),后者由Introduction構(gòu)成。PointCutAdvisor主要是根據(jù)PointCut中制定的Target Objects的方法在調(diào)用(前,后,around,throws, after-return等)時引入新的Aspect中的methods, 而IntroductionAdvisor主要是引入新的接口到Targets對象中。
1、 PointcutAdvisor: Advice和Pointcut,默認(rèn)實現(xiàn)為DefaultPointcutAdvisor, 還有NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。
其中NameMacthMethodPointCutAdvisor、RegexpMethodPointCutAdvisor 可以對比常用的PointCut類有NameMatchedMethodPointCut和JdkRegexMethodPointCut。 2、 IntroductionAdvisor :默認(rèn)實現(xiàn)為DefaultIntroductionAdvisor,這個主要與Introduction有關(guān),可以參考上面的例子
— 目標(biāo)對象(Target Object):包含連接點的對象,也被稱作被通知或被代理對象。 — AOP代理(AOP Proxy):AOP框架創(chuàng)建的對象,包含通知。在Spring中,AOP代理可以是JDK動態(tài)代理或CGLIB代理。如ProxyFactory,ProxyFactoryBean, 下面會進(jìn)行詳細(xì)說明 — 編織(Weaving):組裝方面來創(chuàng)建一個被通知對象。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在運行時完成。Spring和其他純Java AOP框架一樣,在運行時完成織入。將Aspect加入到程序代碼的過程,對于Spring AOP,由ProxyFactory或者ProxyFactoryBean負(fù)責(zé)織入動作。 通過ProxyFactory可以將對符合條件的類調(diào)用時添加上Aspect。 或者 可使用XML聲明式 ProxyFactoryBean:需要設(shè)定 target,interceptorNames(可以是Advice或者Advisor,注意順序, 對接口代理需設(shè)置proxyInterfaces 注意:一個ProxyFactoryBean只能指定一個代理目標(biāo),不是很方便,這就產(chǎn)生了自動代理。通過自動代理,可以實現(xiàn)自動為多個目標(biāo)Bean實現(xiàn)AOP代理、避免客戶端直接訪問目標(biāo)Bean(即getBean返回的都是Bean的代理對象)。spring的自動代理是通過BeanPostProcessor實現(xiàn)的,容器載入xml配置后會修改bean為代理Bean,而id不變。
ApplicationContext可以直接檢測到定義在容器中的BeanPostProcessor,BeanFactory需要手動添加。
2.DefaultAdvisorAutoProxyCreator: DefaultAdvisorAutoProxyCreator和BeanNameAutoProxyCreator不同的是,前者只和Advisor 匹配, 該類實現(xiàn)了BeanPostProcessor接口。當(dāng)應(yīng)用上下文讀入所有的Bean的配置信息后,該類將掃描上下文,尋找所有的Advisor,他將這些Advisor應(yīng)用到所有符合切入點的Bean中。所以下面的xml中沒有綁定也無需綁定DefaultAdvisorAutoProxyCreator與Advisor的關(guān)系。
在使用Aonnotation的時候,需要進(jìn)行在ApplicationContext.xml中進(jìn)行配置:
綜上,Spring下AOP的配置與實現(xiàn),BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator已經(jīng)部分簡化了AOP配置,然而還是很繁瑣: 首先要編寫xxxAdvice類(需要自己實現(xiàn)MethodBeforeAdvice、MethodAfterAdvice、 ThrowsAdvice、MethodInterceptor接口之一),然后還要在xml中配置Advisor,還要在Advisor中注入 Advice,最后還要將Advisor加入ProxyFactoryBean、BeanNameAutoProxyCreator或者 DefaultAdvisorAutoProxyCreator中 。 實際上AOP不止Spring進(jìn)行了實現(xiàn),還有AspectJ,后者對AOP中的概念實現(xiàn)比較徹底,可以看上面,而Spring中對AOP的方方面面進(jìn)行簡化,拿上面定義的regexpFilterPointcutAdvisor是一種Advisor包含了PointCut和Advice,而此處的PointCut就是pattern屬性的值了,沒有特定的PointCut Bean定義,而advice定義了Bean。而其他概念A(yù)spect, JoinPoint都融匯于Advice的實現(xiàn)中即Advisor(MethodBeforeAdvice等和MethodIntector接口的實現(xiàn)類)或IntroductionInterceptor了。
較詳細(xì)的介紹AOP http://blog./uid-21547257-id-97998.html
http://www.cnblogs.com/tazi/articles/2306160.html
http://blog.csdn.net/a906998248/article/details/7514969 http:///forum/blogPost/list/2466.html;jsessionid=AC7C2BDCBF5B19BE4327AD26D40C3CFF |
|