日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Spring IOC和AOP 原理徹底搞懂

 liang1234_ 2019-04-24

 本博中關(guān)于spring的文章:Spring IOC和AOP原理,Spring事務(wù)原理探究,Spring配置文件屬性詳解Spring中的代理模式


Spring提供了很多輕量級(jí)應(yīng)用開(kāi)發(fā)實(shí)踐的工具集合,這些工具集以接口、抽象類(lèi)、或工具類(lèi)的形式存在于Spring中。通過(guò)使用這些工具集,可以實(shí)現(xiàn)應(yīng)用程序與各種開(kāi)源技術(shù)及框架間的友好整合。比如有關(guān)jdbc封裝的數(shù)據(jù)訪問(wèn)工具Spring JDBC,有關(guān)編寫(xiě)單元測(cè)試的spring test包以及spring-mock,有關(guān)訪問(wèn)動(dòng)態(tài)腳本語(yǔ)言的Spring Script,另外還有發(fā)送郵件的工具Spring Mail、日程及任務(wù)處理工具Spring scheduling等。 可以這么說(shuō),大多數(shù)企業(yè)級(jí)應(yīng)用開(kāi)發(fā)中經(jīng)常涉及到的一些通用的問(wèn)題,都可以通過(guò)Spring提供的一些實(shí)用工具包輕松解決

依賴(lài)注入的三種方式:(1)接口注入(2)Construct注入(3)Setter注入

控制反轉(zhuǎn)(IoC)與依賴(lài)注入(DI)是同一個(gè)概念,引入IOC的目的:(1)脫開(kāi)、降低類(lèi)之間的耦合;(2)倡導(dǎo)面向接口編程、實(shí)施依賴(lài)倒換原則; (3)提高系統(tǒng)可插入、可測(cè)試、可修改等特性。
具體做法:(1)將bean之間的依賴(lài)關(guān)系盡可能地抓換為關(guān)聯(lián)關(guān)系;
(2)將對(duì)具體類(lèi)的關(guān)聯(lián)盡可能地轉(zhuǎn)換為對(duì)Java interface的關(guān)聯(lián),而不是與具體的服務(wù)對(duì)象相關(guān)聯(lián);
(3)Bean實(shí)例具體關(guān)聯(lián)相關(guān)Java interface的哪個(gè)實(shí)現(xiàn)類(lèi)的實(shí)例,在配置信息的元數(shù)據(jù)中描述;
(4)由IoC組件(或稱(chēng)容器)根據(jù)配置信息,實(shí)例化具體bean類(lèi)、將bean之間的依賴(lài)關(guān)系注入進(jìn)來(lái)。

org.springframework.beans及org.springframework.context包是Spring IoC容器的基礎(chǔ)。BeanFactory提供的高級(jí)配置機(jī)制,使得管理任何性質(zhì)的對(duì)象成為可能。ApplicationContext是BeanFactory的擴(kuò)展,功能得到了進(jìn)一步增強(qiáng),比如更易與Spring AOP集成、消息資源處理(國(guó)際化處理)、事件傳遞及各種不同應(yīng)用層的context實(shí)現(xiàn)(如針對(duì)web應(yīng)用的WebApplicationContext)。 簡(jiǎn)而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext則增加了更多支持企業(yè)核心內(nèi)容的功能。ApplicationContext完全由BeanFactory擴(kuò)展而來(lái),因而B(niǎo)eanFactory所具備的能力和行為也適用于ApplicationContext。

IoC容器負(fù)責(zé)容納bean,并對(duì)bean進(jìn)行管理。在Spring中,BeanFactory是IoC容器的核心接口。它的職責(zé)包括:實(shí)例化、定位、配置應(yīng)用程序中的對(duì)象及建立這些對(duì)象間的依賴(lài)。Spring為我們提供了許多易用的BeanFactory實(shí)現(xiàn),XmlBeanFactory就是最常用的一個(gè)。該實(shí)現(xiàn)將以XML方式描述組成應(yīng)用的對(duì)象以及對(duì)象間的依賴(lài)關(guān)系。XmlBeanFactory類(lèi)將持有此XML配置元數(shù)據(jù),并用它來(lái)構(gòu)建一個(gè)完全可配置的系統(tǒng)或應(yīng)用。

實(shí)現(xiàn)化容器:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. Resource resource = new FileSystemResource("beans.xml");  
  2. BeanFactory factory = new XmlBeanFactory(resource);  
  3. ... 或...  
  4. ClassPathResource resource = new ClassPathResource("beans.xml");  
  5. BeanFactory factory = new XmlBeanFactory(resource);  
  6. ... 或...  
  7. ApplicationContext context = new ClassPathXmlApplicationContext(  
  8.         new String[] {"applicationContext.xml""applicationContext-part2.xml"});  
  9. // of course, an ApplicationContext is just a BeanFactory  
  10. BeanFactory factory = (BeanFactory) context;  
將XML配置文件分拆成多個(gè)部分是非常有用的。為了加載多個(gè)XML文件生成一個(gè)ApplicationContext實(shí)例,可以將文件路徑作為字符串?dāng)?shù)組傳給ApplicationContext構(gòu)造器。而bean factory將通過(guò)調(diào)用bean defintion reader從多個(gè)文件中讀取bean定義。
通常情況下,Spring團(tuán)隊(duì)傾向于上述做法,因?yàn)檫@樣各個(gè)配置并不會(huì)查覺(jué)到它們與其他配置文件的組合。另外一種方法是使用一個(gè)或多個(gè)的<import/>元素來(lái)從另外一個(gè)或多個(gè)文件加載bean定義。所有的<import/>元素必須放在<bean/>元素之前以完成bean定義的導(dǎo)入。 讓我們看個(gè)例子:
<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個(gè)外部文件:services.xml、messageSource.xmlthemeSource.xml來(lái)加載bean定義。這里采用的都是相對(duì)路徑,因此,此例中的services.xml一定要與導(dǎo)入文件放在同一目錄或類(lèi)路徑,而messageSource.xmlthemeSource.xml的文件位置必須放在導(dǎo)入文件所在目錄下的resources目錄中。正如你所看到的那樣,開(kāi)頭的斜杠‘/’實(shí)際上可忽略。因此不用斜杠‘/’可能會(huì)更好一點(diǎn)。
根據(jù)Spring XML配置文件的Schema(或DTD),被導(dǎo)入文件必須是完全有效的XML bean定義文件,且根節(jié)點(diǎn)必須為<beans/> 元素。

BeanFactory和FactoryBean的區(qū)別,簡(jiǎn)而言之,BeanFactory是加載的容器,加載一切的BEAN,而FactoryBean用于創(chuàng)建代理類(lèi)
===============================================================上面已講到
 BeanFactory它的職責(zé)包括:實(shí)例化、定位、配置應(yīng)用程序中的對(duì)象及建立這些對(duì)象間的依賴(lài)
FactoryBean(通常情況下,bean無(wú)須自己實(shí)現(xiàn)工廠模式,Spring容器擔(dān)任工廠角色;但少數(shù)情況下,容器中的bean本身就是工廠,其作用是產(chǎn)生其它bean實(shí)例),作用是產(chǎn)生其他bean實(shí)例。通常情況下,這種bean沒(méi)有什么特別的要求,僅需要提供一個(gè)工廠方法,該方法用來(lái)返回其他bean實(shí)例。由工廠bean產(chǎn)生的其他bean實(shí)例,不再由Spring容器產(chǎn)生,因此與普通bean的配置不同,不再需要提供class元素。

ProxyFactoryBean用于創(chuàng)建代理(根據(jù)Advisor生成的Bean,也就是TargetBean的代理)
我們的Advisor,PointCut等等,其最終目的都是為了創(chuàng)建這個(gè)代理。
===============================================================下面將講到

AOP全名Aspect-Oriented Programming,中文直譯為面向切面(方面)編程,當(dāng)前已經(jīng)成為一種比較成熟的編程思想,可以用來(lái)很好的解決應(yīng)用系統(tǒng)中分布于各個(gè)模塊的交叉關(guān)注點(diǎn)問(wèn)題。在輕量級(jí)的J2EE中應(yīng)用開(kāi)發(fā)中,使用AOP來(lái)靈活處理一些具有橫切性質(zhì)的系統(tǒng)級(jí)服務(wù),如事務(wù)處理、安全檢查、緩存、對(duì)象池管理等,已經(jīng)成為一種非常適用的解決方案。 AOP中比較重要的概念有:Aspect、JoinPoint、PonitCut、Advice、Introduction、Weave、Target Object、Proxy Object等

引介(Introduction)是指給一個(gè)現(xiàn)有類(lèi)添加方法或字段屬性,引介還可以在不改變現(xiàn)有類(lèi)代碼的情況下,讓現(xiàn)有的Java類(lèi)實(shí)現(xiàn)新的接口,或者為其指定一個(gè)父類(lèi)從而實(shí)現(xiàn)多重繼承。相對(duì)于增強(qiáng)(Advice)可以動(dòng)態(tài)改變程序的功能或流程來(lái)說(shuō),引介(Introduction)則用來(lái)改變一個(gè)類(lèi)的靜態(tài)結(jié)構(gòu)。比如我們可以讓一個(gè)現(xiàn)有為實(shí)現(xiàn)java.lang.Cloneable接口,從而可以通過(guò)clone()方法復(fù)制這個(gè)類(lèi)的實(shí)例。

攔截器是用來(lái)實(shí)現(xiàn)對(duì)連接點(diǎn)進(jìn)行攔截,從而在連接點(diǎn)前或后加入自定義的切面模塊功能。在大多數(shù)JAVA的AOP框架實(shí)現(xiàn)中,都是使用攔截器來(lái)實(shí)現(xiàn)字段訪問(wèn)及方法調(diào)用的攔截(interception)。所用作用于同一個(gè)連接點(diǎn)的多個(gè)攔截器組成一個(gè)連接器鏈(interceptor chain),鏈接上的每個(gè)攔截器通常會(huì)調(diào)用下一個(gè)攔截器。Spring AOP及JBoos AOP實(shí)現(xiàn)都是采用攔截器來(lái)實(shí)現(xiàn)的。

面向?qū)ο缶幊蹋∣OP)解決問(wèn)題的重點(diǎn)在于對(duì)具體領(lǐng)域模型的抽象,而面向切面編程(AOP)解決問(wèn)題的關(guān)鍵則在于對(duì)關(guān)注點(diǎn)的抽象。也就是說(shuō),系統(tǒng)中對(duì)于一些需要分散在多個(gè)不相關(guān)的模塊中解決的共同問(wèn)題,則交由AOP來(lái)解決;AOP能夠使用一種更好的方式來(lái)解決OOP不能很好解決的橫切關(guān)注點(diǎn)問(wèn)題以及相關(guān)的設(shè)計(jì)難題來(lái)實(shí)現(xiàn)松散耦合。因此,面向方面編程 (AOP) 提供另外一種關(guān)于程序結(jié)構(gòu)的思維完善了OOP,是OOP的一種擴(kuò)展技術(shù),彌補(bǔ)補(bǔ)了OOP的不足。


AOP概念詳解:注意以下實(shí)例<aop:開(kāi)頭的AspectJ的概念,Spring沒(méi)有分的這么細(xì)。

  — 方面(Aspect):一個(gè)關(guān)注點(diǎn)的模塊化,這個(gè)關(guān)注點(diǎn)實(shí)現(xiàn)可能另外橫切多個(gè)對(duì)象。事務(wù)管理是一個(gè)很好的橫切關(guān)注點(diǎn)例子。方面用Spring的Advisor或攔截器實(shí)現(xiàn), 然后可以通過(guò)@Aspect標(biāo)注或在applictionContext.xml中進(jìn)行配置: 

      <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"

  — 連接點(diǎn)(Joinpoint):程序執(zhí)行過(guò)程中的行為,如方法的調(diào)用或特定的異常被拋出,在代碼上有JoinPoint類(lèi)和ProceedingJoinPoint類(lèi),如下所示,可以通過(guò)JoinPoint獲取很多參數(shù),JoinPoint一般用在Advice實(shí)現(xiàn)方法中作為參數(shù)傳入,ProceedingJoinPoint用于實(shí)現(xiàn)圍繞Advice的參數(shù)傳入。  通過(guò)下面JoinPoint的接口可以看出通過(guò)JoinPoint可以得到代理對(duì)象和Target對(duì)象。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.aspectj.lang;  
  2. import org.aspectj.lang.reflect.SourceLocation;  
  3. public interface JoinPoint {  
  4.     String toString();         //連接點(diǎn)所在位置的相關(guān)信息  
  5.     String toShortString();     //連接點(diǎn)所在位置的簡(jiǎn)短相關(guān)信息  
  6.     String toLongString();     //連接點(diǎn)所在位置的全部相關(guān)信息  
  7.     Object getThis();         //返回AOP代理對(duì)象  
  8.     Object getTarget();       //返回目標(biāo)對(duì)象  
  9.     Object[] getArgs();       //返回被通知方法參數(shù)列表  
  10.     Signature getSignature();  //返回當(dāng)前連接點(diǎn)簽名  
  11.     SourceLocation getSourceLocation();//返回連接點(diǎn)方法所在類(lèi)文件中的位置  
  12.     String getKind();        //連接點(diǎn)類(lèi)型  
  13.     StaticPart getStaticPart(); //返回連接點(diǎn)靜態(tài)部分  
  14. }  
  15.   
  16. public interface ProceedingJoinPoint extends JoinPoint {  
  17.     public Object proceed() throws Throwable;  
  18.     public Object proceed(Object[] args) throws Throwable;  
  19. }  

      — 切入點(diǎn)(Pointcut):指定一個(gè)Adivce將被引發(fā)的一系列連接點(diǎn)的集合。AOP框架必須允許開(kāi)發(fā)者指定切入點(diǎn),例如,使用正則表達(dá)式。

          xml中配置:

<aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> 

          或使用Annoation :@pointcut("execution * transfer(..)")并用一個(gè)返回值為void,方法體為空的方法來(lái)命名切入點(diǎn)如:  private void anyOldTransfer(){}

     之后就可以在Advice中引用,如: @AfterReturning(pointcut="anyOldTransfer()", returning="reVal")  

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.springframework.aop;  
  2. public interface Pointcut {  
  3.     ClassFilter getClassFilter();  
  4.     MethodMatcher getMethodMatcher();  
  5.     Pointcut TRUE = TruePointcut.INSTANCE;  
  6. }  
  7. package org.springframework.aop;  
  8. public interface ClassFilter {  
  9.      boolean matches(Class<?> clazz);//如果clazz與我們關(guān)注的現(xiàn)象相符時(shí)返回true,負(fù)責(zé)返回false  
  10.      ClassFilter TRUE = TrueClassFilter.INSTANCE;//靜態(tài)參數(shù) 如果類(lèi)型對(duì)于要撲捉的Pointcut來(lái)說(shuō)無(wú)所謂,可將此參數(shù)傳遞給Pointcut  
  11. }  
  12. package org.springframework.aop;  
  13. public interface MethodMatcher {  
  14.    boolean matches(Method method, Class<?> targetClass);  
  15.   
  16.  /** 
  17.   * 是否對(duì)參數(shù)值敏感 
  18.   * 如果為false表明匹配時(shí)不需要判斷參數(shù)值(參數(shù)值不敏感),稱(chēng)之為StaticMethodMatcher,這時(shí)只有 
  19.   * matches(Method method, Class<?> targetClass); 被執(zhí)行,執(zhí)行結(jié)果可以緩存已提高效率。 
  20.   * 如果為true表明匹配時(shí)需要判斷參數(shù)值(參數(shù)值敏感),稱(chēng)之為DynamicMethodMatcher,這時(shí)先執(zhí)行 
  21.   * matches(Method method, Class<?> targetClass);如果返回true,然后再執(zhí)行 
  22.   * boolean matches(Method method, Class<?> targetClass, Object[] args);已做進(jìn)一步判斷 
  23.   *  
  24.   */  
  25.  boolean isRuntime();  
  26.  boolean matches(Method method, Class<?> targetClass, Object[] args);  
  27.  MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;  
  28. }  

關(guān)于PointCut中使用的execution的說(shuō)明:

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定義一個(gè)方法時(shí)的樣子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就可以了。

其中,除ret-type-pattern和name-pattern之外,其他都是可選的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值為任意類(lèi)型;方法名任意;參數(shù)不作限制的所有方法。

常見(jiàn)的PointCut結(jié)構(gòu)圖:


  — 通知(Advice):在特定的連接點(diǎn),AOP框架執(zhí)行的動(dòng)作。各種類(lèi)型的通知包括“around”、“before”和“throws”通知。通知類(lèi)型將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護(hù)一個(gè)“圍繞”連接點(diǎn)的攔截器鏈。Advice中必須用到PointCut

     在xml中配置,配置中的method為Aspect實(shí)現(xiàn)類(lèi)中的方法名,使用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.*.*(..))")  

注意

  • AfterReturning 增強(qiáng)處理處理只有在目標(biāo)方法成功完成后才會(huì)被織入。
  • After 增強(qiáng)處理不管目標(biāo)方法如何結(jié)束(保存成功完成和遇到異常中止兩種情況),它都會(huì)被織入。

使用方法攔截器的around通知,需實(shí)現(xiàn)接口MethodInterceptor:

public interface MethodInterceptor extends Interceptor {

    Object invoke(MethodInvocation invocation) throws Throwable;

}

invoke()方法的MethodInvocation 參數(shù)暴露將被調(diào)用的方法、目標(biāo)連接點(diǎn)、AOP代理和傳遞給被調(diào)用方法的參數(shù)。 invoke()方法應(yīng)該返回調(diào)用的結(jié)果:連接點(diǎn)的返回值。

一個(gè)簡(jiǎn)單的MethodInterceptor實(shí)現(xiàn)看起來(lái)如下:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public class DebugInterceptor implements MethodInterceptor {  
  2.     public Object invoke(MethodInvocation invocation) throws Throwable {  
  3.         System.out.println("Before: invocation=[" + invocation + "]");  
  4.         Object rval = invocation.proceed();  
  5.         System.out.println("Invocation returned");  
  6.         return rval;  
  7.     }  
  8. }  

注意MethodInvocation的proceed()方法的調(diào)用。這個(gè)調(diào)用會(huì)應(yīng)用到目標(biāo)連接點(diǎn)的攔截器鏈中的每一個(gè)攔截器。大部分?jǐn)r截器會(huì)調(diào)用這個(gè)方法,并返回它的返回值。但是, 一個(gè)MethodInterceptor,和任何around通知一樣,可以返回不同的值或者拋出一個(gè)異常,而不調(diào)用proceed方法。但是,沒(méi)有好的原因你要這么做。

Before通知:需實(shí)現(xiàn)MethodBeforeAdvice接口

public interface MethodBeforeAdvice extends BeforeAdvice {

    void before(Method m, Object[] args, Object target) throws Throwable;

}

Throw通知,需實(shí)現(xiàn)ThrowsAdvice接口

After Returning通知須直線AfterReturningAdvice接口

public interface AfterReturningAdvice extends Advice {

    void afterReturning(Object returnValue, Method m, Object[] args, Object target)

            throws Throwable;

}

       — 引入(Introduction):添加方法或字段到被通知的類(lèi),引入新的接口到任何被通知的對(duì)象。例如,你可以使用一個(gè)引入使任何對(duì)象實(shí)現(xiàn)IsModified接口,來(lái)簡(jiǎn)化緩存。使用introduction要有三個(gè)步驟(1)聲明新接口(2)創(chuàng)建自己的IntrouductionInterceptor通過(guò)Implements IntroductionInterceptor或extends DelegatingIntroductionInterceptor 并同時(shí)implements(1)中聲明的接口 (3)將新接口和自定義的IntroductionInterceptor配置到DefaultIntroductionAdvisor中,然后將前三者配置到ProxyFactoryBean中。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public interface IOtherBean {  
  2.     public void doOther();  
  3. }  
  4.   
  5. public class SomeBeanIntroductionInterceptor implements IOtherBean, IntroductionInterceptor {  
  6.   
  7.     public void doOther() {  
  8.         System.out.println("doOther!");  
  9.     }  
  10.   
  11.     public Object invoke(MethodInvocation invocation) throws Throwable {  
  12.           
  13.         //判斷調(diào)用的方法是否為指定類(lèi)中的方法  
  14.         if ( implementsInterface(invocation.getMethod().getDeclaringClass()) ) {  
  15.             return invocation.getMethod().invoke(this, invocation.getArguments());  
  16.         }  
  17.           
  18.         return invocation.proceed();  
  19.     }  
  20.       
  21.     /** 
  22.      * 判斷clazz是否為給定接口IOtherBean的實(shí)現(xiàn) 
  23.      */  
  24.     public boolean implementsInterface(Class clazz) {  
  25.           
  26.         return clazz.isAssignableFrom(IOtherBean.class);  
  27.     }  
  28. }  

[html] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. <!-- 目標(biāo)對(duì)象 -->  
  2. <bean id="someBeanTarget" class="aop.spring.introduction.SomeBeanImpl" />  
  3. <!-- 通知 -->  
  4. <bean id="someBeanAdvice" class="aop.spring.introduction.SomeBeanIntroductionInterceptor" />  
  5. <!-- 通知者,只能以構(gòu)造器方法注入-->  
  6. <bean id="introductionAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">  
  7.     <constructor-arg ref="someBeanAdvice" />  
  8.     <constructor-arg value="aop.spring.introduction.IOtherBean" />      
  9. </bean>  
  10.       
  11. <!-- 代理 (將我們的切面織入到目標(biāo)對(duì)象)-->  
  12. <bean id="someBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  13.     <!-- 若目標(biāo)對(duì)象實(shí)現(xiàn)了代理接口,則可以提供代理接口的配置 -->  
  14.     <property name="proxyInterfaces"  value="aop.spring.introduction.ISomeBean" />  
  15.     <!-- 配置目標(biāo)對(duì)象 -->  
  16.     <property name="target" ref="someBeanTarget" />  
  17.     <!-- 配置切面 -->  
  18.     <property name="interceptorNames">  
  19.         <list>  
  20.             <value>introductionAdvisor</value>  
  21.         </list>  
  22.     </property>  
  23. </bean>  


    — 攔截器(Advisor )常用的有PointCutAdvisor和IntroudtionAdvisor。前者Advisor有PointCut和Advice組成,滿足Poincut(指定了哪些方法需要增強(qiáng)),則執(zhí)行相應(yīng)的Advice(定義了增強(qiáng)的功能),后者由Introduction構(gòu)成。PointCutAdvisor主要是根據(jù)PointCut中制定的Target Objects的方法在調(diào)用(前,后,around,throws, after-return等)時(shí)引入新的Aspect中的methods, 而IntroductionAdvisor主要是引入新的接口到Targets對(duì)象中。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public interface PointcutAdvisor {  
  2.     Pointcut getPointcut();  
  3.     Advice getAdvice();  
  4. }  

1、 PointcutAdvisor: Advice和Pointcut,默認(rèn)實(shí)現(xiàn)為DefaultPointcutAdvisor, 還有NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。 

 其中NameMacthMethodPointCutAdvisor、RegexpMethodPointCutAdvisor 可以對(duì)比常用的PointCut類(lèi)有NameMatchedMethodPointCut和JdkRegexMethodPointCut。
 前者需要注入mappedName和advice屬性,后者需要注入pattern和advice屬性。其中mappedName和pattern是直接配置的值,而advice需要自己實(shí)現(xiàn)具體的advice,可見(jiàn)實(shí)現(xiàn)advisor的時(shí)候,不需要實(shí)現(xiàn)PointCut,一般PointCut只需要配置就好了,不需要具體實(shí)現(xiàn)類(lèi)
 mappedName指明了要攔截的方法名,pattern按照正則表達(dá)式的方法指明了要攔截的方法名,advice定義了一個(gè)增強(qiáng)(需要自己實(shí) 現(xiàn)MethodBeforeAdvice、  MethodAfterAdvice、ThrowsAdvice、MethodInterceptor接口之 一)。然后在ProxyFactoryBean的攔截器(interceptorNames)中注入這個(gè)PointCutAdvisor即可,如上面這個(gè)ProxyFactoryBean是一個(gè)靜態(tài)代理,只能代理一個(gè)類(lèi)給加上AOP,那么這個(gè)靜態(tài)代理需要注入有目標(biāo)對(duì)象,目標(biāo)對(duì)象的接口,和interceptorsNames

2、 IntroductionAdvisor :默認(rèn)實(shí)現(xiàn)為DefaultIntroductionAdvisor,這個(gè)主要與Introduction有關(guān),可以參考上面的例子


  — 目標(biāo)對(duì)象(Target Object):包含連接點(diǎn)的對(duì)象,也被稱(chēng)作被通知或被代理對(duì)象。

  — AOP代理(AOP Proxy):AOP框架創(chuàng)建的對(duì)象,包含通知。在Spring中,AOP代理可以是JDK動(dòng)態(tài)代理或CGLIB代理。如ProxyFactory,ProxyFactoryBean, 下面會(huì)進(jìn)行詳細(xì)說(shuō)明    

  — 編織(Weaving):組裝方面來(lái)創(chuàng)建一個(gè)被通知對(duì)象。這可以在編譯時(shí)完成(例如使用AspectJ編譯器),也可以在運(yùn)行時(shí)完成。Spring和其他純Java AOP框架一樣,在運(yùn)行時(shí)完成織入。將Aspect加入到程序代碼的過(guò)程,對(duì)于Spring AOP,由ProxyFactory或者ProxyFactoryBean負(fù)責(zé)織入動(dòng)作。 

    通過(guò)ProxyFactory可以將對(duì)符合條件的類(lèi)調(diào)用時(shí)添加上Aspect。

    或者 可使用XML聲明式 ProxyFactoryBean:需要設(shè)定 target,interceptorNames(可以是Advice或者Advisor,注意順序, 對(duì)接口代理需設(shè)置proxyInterfaces 

注意:一個(gè)ProxyFactoryBean只能指定一個(gè)代理目標(biāo),不是很方便,這就產(chǎn)生了自動(dòng)代理。通過(guò)自動(dòng)代理,可以實(shí)現(xiàn)自動(dòng)為多個(gè)目標(biāo)Bean實(shí)現(xiàn)AOP代理、避免客戶(hù)端直接訪問(wèn)目標(biāo)Bean(即getBean返回的都是Bean的代理對(duì)象)。spring的自動(dòng)代理是通過(guò)BeanPostProcessor實(shí)現(xiàn)的,容器載入xml配置后會(huì)修改bean為代理Bean,而id不變。 

ApplicationContext可以直接檢測(cè)到定義在容器中的BeanPostProcessor,BeanFactory需要手動(dòng)添加。 
有2種常用的BeanPostProcessor: 
1.BeanNameAutoProxyCreator 故名思議,BeanName需要注入的兩個(gè)屬性有BeanNames和interceptorNames

[html] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. <bean id="loginBeforeAdvisor" .../>    
  2. <bean id="loginThrowsAdvisor" .../>    
  3. <bean  class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">    
  4.         <!-- 注入目標(biāo)Bean -->    
  5.         <property name="beanNames" value="*Service">    
  6.         </property>    
  7.         <property name="interceptorNames">    
  8.             <list>    
  9.                 <value>loginBeforeAdvisor</value>    
  10.                 <value>loginThrowsAdvisor</value>    
  11.             </list>    
  12.         </property>    
  13. </bean>    

2.DefaultAdvisorAutoProxyCreator: DefaultAdvisorAutoProxyCreator和BeanNameAutoProxyCreator不同的是,前者只和Advisor 匹配, 該類(lèi)實(shí)現(xiàn)了BeanPostProcessor接口。當(dāng)應(yīng)用上下文讀入所有的Bean的配置信息后,該類(lèi)將掃描上下文,尋找所有的Advisor,他將這些Advisor應(yīng)用到所有符合切入點(diǎn)的Bean中。所以下面的xml中沒(méi)有綁定也無(wú)需綁定DefaultAdvisorAutoProxyCreator與Advisor的關(guān)系。

[html] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www./dtd/spring-beans.dtd">  
  3. <beans>  
  4.      <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>  
  5.      <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">  
  6.           <constructor-arg>  
  7.                <value>5000</value>  
  8.           </constructor-arg>  
  9.      </bean>  
  10.      <!-- 使用RegexpMethodPointcutAdvisor來(lái)匹配切入點(diǎn)完成個(gè)一個(gè)Advisor; -->  
  11.      <bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
  12.           <property name="pattern">  
  13.                <!-- 匹配的名字為方法名-->  
  14.                <value>.*buy.*</value>  
  15.           </property>  
  16.           <property name="advice">  
  17.                <ref bean="performanceThresholdInterceptor"/>  
  18.           </property>  
  19.      </bean>  
  20.      <bean id="defaultAdvisorAutoProxyCreator"  
  21.      class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />  
  22. </beans>  

在使用Aonnotation的時(shí)候,需要進(jìn)行在ApplicationContext.xml中進(jìn)行配置:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www./schema/beans"  
  3.        xmlns:xsi="http://www./2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www./schema/aop"        
  5.        xsi:schemaLocation="http://www./schema/beans  
  6.            http://www./schema/beans/spring-beans-3.0.xsd  
  7.            http://www./schema/aop  
  8.        http://www./schema/beans/spring-aop-3.0.xsd">  
  9.         <!-- 啟動(dòng)對(duì)@AspectJ注解的支持 -->  
  10.         <aop:aspectj-autoproxy/>  
  11. </beans>  


綜上,Spring下AOP的配置與實(shí)現(xiàn),BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator已經(jīng)部分簡(jiǎn)化了AOP配置,然而還是很繁瑣: 首先要編寫(xiě)xxxAdvice類(lèi)(需要自己實(shí)現(xiàn)MethodBeforeAdvice、MethodAfterAdvice、 ThrowsAdvice、MethodInterceptor接口之一),然后還要在xml中配置Advisor,還要在Advisor中注入 Advice,最后還要將Advisor加入ProxyFactoryBean、BeanNameAutoProxyCreator或者 DefaultAdvisorAutoProxyCreator中

實(shí)際上AOP不止Spring進(jìn)行了實(shí)現(xiàn),還有AspectJ,后者對(duì)AOP中的概念實(shí)現(xiàn)比較徹底,可以看上面,而Spring中對(duì)AOP的方方面面進(jìn)行簡(jiǎn)化,拿上面定義的regexpFilterPointcutAdvisor是一種Advisor包含了PointCut和Advice,而此處的PointCut就是pattern屬性的值了,沒(méi)有特定的PointCut Bean定義,而advice定義了Bean。而其他概念A(yù)spect, JoinPoint都融匯于Advice的實(shí)現(xiàn)中即Advisor(MethodBeforeAdvice等和MethodIntector接口的實(shí)現(xiàn)類(lèi))或IntroductionInterceptor了。




較詳細(xì)的介紹AOP http://blog./uid-21547257-id-97998.html

Advice的類(lèi)型及實(shí)現(xiàn)細(xì)節(jié):http://blog.csdn.net/saintlu/article/details/3340190

http://www.cnblogs.com/tazi/articles/2306160.html  

http://blog.csdn.net/a906998248/article/details/7514969

http:///forum/blogPost/list/2466.html;jsessionid=AC7C2BDCBF5B19BE4327AD26D40C3CFF

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多