<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-193  評論-715  文章-1  trackbacks-0

    在閱讀此文之前請你熟悉一些IOC的知識,同時了解AOP的概念。

    Spring 中所有的通知都是以 Java 類的形式編寫的。 Spring 是采用運行期的方式來將切面織入到系統中的。

    代理 Bean 只有在第一次被應用系統需要的時候才被創建。 Spring 有兩種方式創建代理: Proxy 類創建代理 ( 實現過接口的目標類 ) 和運用 CGLIB 庫創建代理 ( 沒有實現過任何接口的目標類 ) 。需要注意兩點: 1 、對接口創建代理優于對類創建代理,因為這樣會產生更加松耦合的系統, 2 、標記為 final 的方法是不能被通知的,因為 Spring 在實現的時候是為目標類產生子類。

    Spring 只支持方法聯接點。

    ?

    ?

    Spring 中通知的類型:

    1 Around???? org.aopalliance.intercept.MethodInterceptor??????? 欄截對目標對象方法的調用

    2 Before?????? org.springframework.aop.MethodBeforAdvice???? 在目標方法被調用之前調用

    3 After ?????? org.springframework.aop.AfterReturningAdvice? 當目標方法被調用之后調用

    4 Thorws???? org.springframework.aop.ThrowsAdvice???? ?????? 當目標方法拋出異常時調用

    ?

    前置通知 實現 MethodBeforeAdvice 接口,該接口有以下方法:

    void befor(Method method,Object []args,Object target) throws Throwable;

    例:

    public class WelcomeAdvice implements MethodBeforeAdvice{

    ?????? public void before(Method method,Object []args,Object target){

    ????????????? System.out.println("Hello,"+((Customer)args[0]).getName());

    ?????? }

    }

    配置文件如下:

    <beans>

    <bean id="aaaTargetObject" class="AAA"/>?? // 目標類 , 這是一個實現某個接口的類

    <bean id="welcomeAdvice" class="WelcomeAdvice"/>? // 通知類

    <bean id="aaa" class="org.springframework.aop.framework.proxyFactoryBean">

    ?????? <property name="interceptorNames">

    ????????????? <list>

    ???????????????????? <value>welcomAdvice</value>

    ????????????? </list>

    ?????? </property>

    ?????? <property name="target">

    ????????????? <ref bean="aaaTargetObject"/>

    ?????? </property>

    </bean>

    </beans>

    ?

    后置通知 實現 AfterReturningAdvice 接口,該接口有以下方法:

    void afterReturning(Object returnValue,Method method,Object []args,Object target) throws Throwable;

    例:

    public class ThankYouAdvice implements AfterReturningAdvice{

    ?????? public void afterReturning(Object returnValue,Method method,Object []args,Object target){

    ????????????? System.out.println("Thank you, come again.");

    ?????? }

    }

    在前置通知和后置通知中都不能改變參數中傳進來的值,改變執行流程的惟一方法就是拋出異常。

    ?

    環繞通知 實現 MethodInterceptor 接口,該接口有以下方法:

    Object invoke(MethodInvocation invocation) throws Throwable;

    環繞通知能夠控制目標方法是否真的被調用,通過調用 MethodInvocation.proceed() 方法來調用目標方法。它還可以讓你控制返回的對象。

    例:

    public class ExampleAroundInterceptor implements MethodInterceptor{

    ?????? public Object invoke(MethodInvocation invocation) throws Throwable{

    ????????????? // 調用之前可以做一些處理

    ????????????? Object returnObject=invocation.proceed();// 調用目標方法

    ????????????? // 調用之后還可以做一些處理

    ????????????? return returnObject;

    ?????? }

    }

    ?

    異常通知 實現 ThrowsAdvice 接口,此接口是一個標示接口,沒有定義必須實現的方法,但是下面兩個方法中必須實現一個:

    void afterThrowing(Throwable throwable);

    void afterThrowing(Method method,Object []args,Object target,Throwable throwable);

    ThrowsAdvice 要處理的異常取決于你的方法定義的異常類型,在一個實現類中,也可以實現多個 afterThrowing 方法,根據拋出的異常類型調用適當的方法。

    ?

    引入通知 給目標對象添加新的方法 ( 以及屬性 )

    ?

    ?

    定義切入點

    切入點 就是應用通知的地方,切入點決定了一個特定的類的特定方法是否滿足一條特定的規則,如果一個方法符合的話,通知就應用到該方法上。 Spring 的切入點可以讓我們以一種靈活的方式定義在什么地方將通知織入到我們的類中。

    切入點的核心接口是 Pointcut 接口,同時它也需要兩個接口支持,如下:

    public interface Pointcut{

    ?????? ClassFilter getClassFilter(); // 決定一個類是否符合要求

    ?????? MethodMatcher getMethodMatcher(); // 決定一個方法是否符合要求

    }

    public interface ClassFilter{

    ?????? boolean matches(Class clazz);

    }

    此接口總是包含一個簡單的 ClassFilter 接口的實現 --ClassFilter.TRUE ,它是規范的適合任何類的 ClassFilter 實例,它適合于只根據方法決定什么時候符合要求的切入點。

    public interface MethodMatcher{

    ?????? boolean matches(Method m,class targetClass);// 靜態的決定一個方法是否被通知織入

    ?????? public boolean isRuntime();// 決定是靜態的還是動態的織入

    ?????? public boolean mathes(Method m,Class targetClass,Object []args);// 動態的決定一個方法是否被通知織入,系統開銷會增加,不推薦使用

    }

    ?

    ?

    大多數的切面是由定義切面行為的通知和定義切面在什么地方執行的切入點給合而成的, Spring 為此提供了 Advisor ,它把通知和切入點組合到一個對象中。接口 PointcutAdvisor 提供了這些功能,接口如下:

    public interface PointcutAdvisor{

    ?????? Pointcut getPointcut();

    ?????? Advice getAdvice();

    }

    大多數 Spring 自帶的切入點都有一個對應的 PointcutAdvisor 。這樣方便你在一個地方定義通知和切入點。

    ?

    使用 Spring 的靜態切入點

    Spring 為創建靜態切入點提供了方便的父類: StaticMethodMatcherPointcut 。如果想自定義靜態切入點的話,繼承這個類,并實現 isMatch 方法就 OK 了。

    Spring 提供了一個靜態切入點的實現類: NameMatchMethodPointcut 。它有如下兩個方法:

    Public void setMappedName(String);

    Public void setMappedNames(String []);

    這個類通過名字映射,上面兩個方法的參數中均可以使用通配符 *

    ?

    規則表達式切入點, Spring 提供了 RegexpMethodPointcut 讓你利用正則表達式的力量來定義切入點。

    符號

    描述

    示例

    .

    匹配任何單個字符

    setFoo. 匹配 setFooB, 但不匹配 setFoo setFooBar

    +

    匹配前一個字符一次或多次

    setFoo.+ 匹配 setFooBar setFooB, 但不匹配 setFoo

    *

    匹配前一個字符 0 次或多次

    setFoo.* 匹配 setFoo,setFooB setFooBar

    \

    匹配任何正則表達式符號

    \.setFoo. 匹配 bar.setFoo, 但不匹配 setFoo

    如果你想匹配所有 setXxx 方法,我們需要使用 .*set*. 模版 ( 第一個通配符匹配任何類名。筆者認為此處《 Spring in action 》一書中有誤,我認為此處應為 .*set.*) 。如果使用 RegexpMethodPointcut ,你需要在你的應用系統中引入 ORO 類庫。

    <bean id=”queryPointcutAdvisor”

    ?????? Class=”org.springframework.aop.support.RegExPointcutAdvisor”>

    ?????? <property name=”pattern”>

    ????????????? <value>.*get.+By.+</value>

    ?????? </property>

    ?????? <property name=”advice”>

    ????????????? <ref bean=”queryInterceptor”/>

    ?????? </property>

    </bean>

    ?

    使用動態切入點

    Spring 提供了一種內置的動態切入點: ControlFlowPointcut 。這個切入點根據線程調用堆棧的信息來匹配方法。也就是說,它可以配置成只有當指定方法或類能在當前線程執行堆棧中找到時,返回 true

    <bean id=”servletPointcut” class=”org.springframework.aop.support.ControlFlowPointcut”>

    ?????? <construct-arg>

    ????????????? <value>javax.servlet.http.HttpServlet</value>

    ?????? </construct-arg>

    </bean>

    <bean id=”servletAdvisor” class=”org.springframework.aop.support.DefaultPointcutAdvisor”>

    ?????? <property name=”advice”>

    ????????????? <ref bean=”servletInterceptor”/>

    ?????? </property>

    ?????? <property name=”pointcut”>

    ????????????? <ref bean=”servletPointcut”/>

    ?????? </property>

    </bean>

    注: ControlFlowPointcut 明顯比其他的動態切入點慢。

    ?

    切入點實施

    Spring 支持在切入點上進行操作 合并與產叉 來創建新的切入點。只有當切入點都匹配時交叉集合才匹配,任何一個切入點匹配都會使合并集合匹配。 Spring 為創建這兩種切入點提供了兩個類:第一個類是 ComposablePointcut 。通過將已有的 ComposablePointcut 、切入點、 MethodMatcher 以及 ClassFilter 對象進行合并或交叉,組裝成一個新的 ComposablePointcut 對象。這可以通過調用 ComposablePointcut 實例的 intersection () union () 方法實現。

    ComposablePointcut cp=new ComposablePoint()

    cp=p.intersection(myPointcut).union(myMethodmatcher);

    為了對兩個 Pointcut 對象進行合并,必須使用 Pointcuts 類。這是一個工具類,它擁有很多操作 Pointcut 對象的靜態方法。如:

    Pointcut union=Pointcuts.union(pointcut1,pointcut2);

    ?

    創建引入

    引入與其他類型的 Spring 通知有所不同。其它類型通知是在方法調用的周圍織入到不同的連接點,而引入則是影響整個類,他們通過給需要消息的類型添加方法和屬性來實現。也就是說,你可以用一個已存在的類讓它實現另外的接口,維持另外的狀態 ( 這也叫混合 ) 。換句話說,引入讓你能夠動態地建立復合對象,提供了多態繼承的好處。

    實現 IntroductionInterceptor

    Spring 通過一個特殊的方法攔截器接口 IntroductionMethodInterceptor 來實現引入。這個接口有一個方法:

    Boolean implementsInterface(Class intf);

    如果 IntroductionMethodInterceptor 是為了實現指定接口,那么方法 implementsInterface 應該返回 true 。就是說,對用這個接口聲明的方法的任何調用將被委托給 IntroductionMethodInterceptor invoke() 方法。 Invoke() 方法負責實現這個方法,不能調用 MethodInvocation.proceed() 。它引入了新的接口,調用目標對象是沒有用的。

    ?

    使用 ProxyBeanFactory

    BeanFactory 對象是一個負責創建其他 JavaBean JavaBean 。屬性列表如下:

    屬性

    使?

    target

    代理的目標對象

    proxyInterfaces

    代理應該實現的接口列表

    interceptorNames

    需要應用到目標對象上的通知 Bean 的名字。可以是攔截器, Advisor 或其他通知類型的名字。這個屬性必須按照在 BeanFactory 中使用的順序設置。

    singleton

    是否返回的是同一個代理實例。如果使用的是狀態通知,應該設置為 false

    aopProxyFactory

    使用的 ProxyFactoryBean 實現

    exposeProxy

    目標對象是否需要得到當前的代理。通過調用 AopContext.getCurrentProxy 實現。記住這樣做會在你的代碼中引入 Spring 專有的 AOP 代碼,所以,盡量避免使用。

    frozen

    一旦工廠被創建,是否可以修改代理的通知。

    optimize

    是否對創建的代理進行優化 ( 僅適用于 CGLIB)

    ProxyTargetClass

    是否代理目標類,而不是實現接口。 ( 需要 CGLIB 支持 )

    大多數情況下我們只用到前三個屬性。

    如果想避免將目標對象暴露給系統中其他 Bean 的話,可以將它聲明為一個內部 Bean

    proxyInterfaces 屬性指定了從工廠中創建的 Bean 需要實現的接口。如:

    <property name=”proxyInterfaces”>

    ?????? <value>com.springinaction.service.CourseService</value>

    </property>

    這樣就讓 ProxyBeanFactory 知道它創建的所有 Bean 都要實現 CourseService 接口。可以像這樣只提供一個接口,也可以用 <list> 提供多個接口。

    interceptorNames 屬性定義了一個應用到目標對象上的 Advisor 或通知 Bean 的列表。目標 Bean 也可以放在此屬性的 <list> 列表的最后,但是最好還是用 Target 屬性設置目標 Bean

    ?

    自動代理

    Spring 有一個自動代理機制,它可以讓容器為我們產生代理。 Spring 有兩個類提供這種服務: BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator

    BeanNameAutoProxyCreator 為匹配一系列名字的 Bean 自動創建代理。它允許在名字的兩端進行通配符匹配。通常用于為符合相同命名規則的 Bean 應用一個或一組切面 ( 主要是解決 target 屬性配置時目標類過多的問題。 ) 如:

    <bean id=”preformanceThresholdProxyCreator

    Class=”org.springframework.aop.framework.autoproxy.BeanNameAutoProxyProlyCreator”>

    <property name=”beanNames”>

    ?????? <list>

    ????????????? <value>*Service</value>

    ?????? </list>

    </property>

    <propery name=”interceptorNames”>

    ?????? <value>performaceThresholdInterceptor</value>

    </property>

    </bean>

    如果 Bean 是一個 Advisor 或攔截器,它將應用到代理對象的所有方法上。如果是通知的話, Advisor 切入點會根據不同 Bean 將通知應用到不同的地方。

    自動代理框架對于代理需要暴露哪些接口作了一些假設。目標對象實現的任何接口代理對象都要暴露出來。如果目標類沒有實現任何接口,那么應用于前面討論過的 ProxyFactoryBean 一樣的規則 動態生成一個子類。

    DefaultAdvisorAutoProxyCreator

    這個類的奇妙之處在于它實現了 BeanPostProcessor 接口。當 ApplicationContext 讀入所有 Bean 的配置信息后, DefaultAdvisorAutoProxyCreator 將掃描上下文,尋找所有的 Advisor 。它將這些 Advisor 應用到所有符合 Advisor 切入點的 Bean 中。這個代理創建器只能與 Advisor 配合使用 ( 我們知道,一個 Advisor 是一個切入點和一個通知的結合體。 DefaultAdvisorAutoProxyCreator 需要 Advisor 來知道哪些 Bean 需要通知。 )

    <bean id=”advisor” class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>

    ?????? <property name=”advice”>

    ????????????? <bean class=”performaceThresholdInterceptor”/>

    ?????? </property>

    ?????? <property name=”pattern”>

    ????????????? <value>.+Service\..+</value>

    ?????? </property>

    </bean>

    <bean id=”autoProxyCreator”

    class=”org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator”/>

    在讀入所有 Bean 的定義信息后, BeanFactory 中的所有 Advisor 將被釋放出來。它們會將它們的通知配置到任何匹配它們的切入點的 Bean ( 這就是它真正的威力 )

    不用顯示地將 Advisor 與其他東西結合,現在只要簡單地定義它們,然后讓它們自動地應用到它們匹配的地方。這樣松耦合 Bean 以及它們的通知就實現了。

    ?

    Spring 也支持通過元數據 (Metadata) 驅動自動代理。這種類型自動代理,代理配置是通過源代碼屬性而不是外部配置文件獲得的。最常見的元數據自動配置是聲明式事務支持。

    posted on 2006-08-15 10:17 Robin's Programming World 閱讀(4487) 評論(5)  編輯  收藏 所屬分類: Java讀書

    評論:
    # re: [讀書筆記]Spring AOP Review 2006-08-15 22:24 | 靜夜思
    相當不錯,收藏了,謝謝分享  回復  更多評論
      
    # re: [讀書筆記]Spring AOP Review 2007-05-09 17:29 | seed
    距spring in action的一樣!能講一講具體的例子嗎?  回復  更多評論
      
    # re: [讀書筆記]Spring AOP Review 2007-05-10 15:15 | Robin's Java World
    @seed
    呵呵,這是我復習時的記錄,具體的例子可以看書。
      回復  更多評論
      
    # re: [讀書筆記]Spring AOP Review[未登錄] 2008-11-19 21:00 | 蟲蟲
    public class ExampleAroundInterceptor implements MethodInterceptor{

    public Object invoke(MethodInvocation invocation) throws Throwable{

    // 調用之前可以做一些處理

    Object returnObject=invocation.proceed();// 調用目標方法

    // 調用之后還可以做一些處理

    return returnObject;

    }
    }

    如何得到他的返回數據信息呢?(你的returnObject)
      回復  更多評論
      
    # re: [讀書筆記]Spring AOP Review[未登錄] 2009-03-19 00:07 | aaa
    謝謝!收藏了  回復  更多評論
      
    主站蜘蛛池模板: 久久精品国产精品亚洲人人| 免费在线观看视频网站| 亚洲一日韩欧美中文字幕在线| 亚洲另类激情综合偷自拍| 在线日韩日本国产亚洲| 免费在线观看黄网站| 精品剧情v国产在免费线观看 | 国产成人精品日本亚洲语音| 久久久国产亚洲精品| 中国亚洲呦女专区| 深夜福利在线视频免费| 一级做a爰全过程免费视频毛片| 日韩毛片在线免费观看| 国产精品亚洲二区在线| 自拍偷自拍亚洲精品偷一| 三年片免费高清版| 久久久久久国产精品免费免费男同 | 亚洲视频.com| 亚洲精品无码专区久久| 麻豆亚洲AV成人无码久久精品| 精品国产污污免费网站入口在线| 久久av免费天堂小草播放| 91成年人免费视频| 午夜寂寞在线一级观看免费| 久久久青草青青国产亚洲免观 | 久久狠狠爱亚洲综合影院| 亚洲一区二区三区丝袜| a一级毛片免费高清在线| 免费a级毛片无码a∨免费软件| 午夜爽爽爽男女免费观看影院| 在线免费观看a级片| 免费一级毛片在播放视频| 久久夜色精品国产噜噜亚洲AV| 精品亚洲成A人无码成A在线观看 | 亚洲色欲色欲www在线播放| a级毛片高清免费视频就| 中文字幕免费视频一| 成人网站免费观看| 亚洲高清免费视频| 亚洲av无码不卡| 亚洲一区二区三区无码国产 |