文章出處

什么是AOP

AOP(Aspect-OrientedProgramming,面向方面編程),它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。

 

AOP使用場景

AOP用來封裝橫切關注點,具體可以在下面的場景中使用:

Authentication 權限

Caching 緩存

Context passing 內容傳遞

Error handling 錯誤處理

Lazy loading 懶加載

Debugging  調試

logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準

Performance optimization 性能優化

Persistence  持久化

Resource pooling 資源池

Synchronization 同步

Transactions 事務

 

Spring AOP底層技術

 

Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪種方式生成由AopProxyFactory根據AdvisedSupport對象的配置來決定。默認的策略是如果目標類是接口,則使用JDK動態代理技術,否則使用Cglib來生成代理。

 

動態代理利用反射的原理,給對象動態的生產代理對象,在執行的方法前后來執行相關內容:

/**
* 動態代理類
* 
* @author yanbin
* 
*/

public class DynamicProxy implements InvocationHandler {

     /** 需要代理的目標類 */
    private Object target;
/**
     * 寫法固定,aop專用:綁定委托對象并返回一個代理類
     * 
     * @param delegate
     * @return
     */

    public Object bind(Object target) {
       this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

     /**
     * @param Object
     *            target:指被代理的對象。
     * @param Method
     *            method:要調用的方法
     * @param Object
     *            [] args:方法調用時所需要的參數
     */

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        // 切面之前執行
        System.out.println("切面之前執行");
        // 執行業務
        result = method.invoke(target, args);
       // 切面之后執行
        System.out.println("切面之后執行");
        return result;
    }
}

CGLIB是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強。采用的是繼承的方式

/**
* 使用cglib動態代理
* 
* @author yanbin
* 
*/

public class CglibProxy implements MethodInterceptor {
 
    private Object target; 

    /**
     * 創建代理對象
     * 
     * @param target
     * @return
     */

    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回調方法
        enhancer.setCallback(this);
        // 創建代理對象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result = null;
        System.out.println("事物開始");
        result = methodProxy.invokeSuper(proxy, args);
        System.out.println("事物結束");
        return result;
    } 
}

 

 

AOP相關概念

方面(Aspect):一個關注點的模塊化,這個關注點實現可能另外橫切多個對象。事務管理是J2EE應用中一個很好的橫切關注點例子。方面用Spring的 Advisor或攔截器實現。

 

連接點(Joinpoint): 程序執行過程中明確的點,如方法的調用或特定的異常被拋出。

 

通知(Advice): 在特定的連接點,AOP框架執行的動作。各種類型的通知包括“around”、“before”和“throws”通知。通知類型將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連接點的攔截器鏈。Spring中定義了四個advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice

 

切入點(Pointcut): 指定一個通知將被引發的一系列連接點的集合。AOP框架必須允許開發者指定切入點:例如,使用正則表達式。 Spring定義了Pointcut接口,用來組合MethodMatcher和ClassFilter,可以通過名字很清楚的理解, MethodMatcher是用來檢查目標類的方法是否可以被應用此通知,而ClassFilter是用來檢查Pointcut是否應該應用到目標類上

 

引入(Introduction): 添加方法或字段到被通知的類。 Spring允許引入新的接口到任何被通知的對象。例如,你可以使用一個引入使任何對象實現 IsModified接口,來簡化緩存。Spring中要使用Introduction, 可有通過DelegatingIntroductionInterceptor來實現通知,通過DefaultIntroductionAdvisor來配置Advice和代理類要實現的接口

 

目標對象(Target Object): 包含連接點的對象。也被稱作被通知或被代理對象。POJO

 

AOP代理(AOP Proxy): AOP框架創建的對象,包含通知。 在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。

 

織入(Weaving): 組裝方面來創建一個被通知對象。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在運行時完成。Spring和其他純Java AOP框架一樣,在運行時完成織入。

 

幾種實現方式

1、基于代理的AOP

2、純簡單java對象切面

3、@Aspect注解形式的

4、注入形式的Aspcet切面

 

面先寫一下幾個基本的類。

接口類:

/**
* 定義一個接口
* @author 陳麗娜
* @version 2015年5月31日上午9:16:50
*/

public interface Sleepable {

/**
* 睡覺方法
* @author 陳麗娜
* @version 2015年5月31日上午9:17:14
*/

void sleep();

}

實現類:

/**
* 陳麗娜 本人實現睡覺接口
* @author 陳麗娜
* @version 2015年5月31日下午4:51:43
*/

public class ChenLliNa implements Sleepable {

@Override
public void sleep() {
// TODO Auto-generated method stub
        System.out.println("乖,該睡覺了!");
}
}

 

增強類:

/**
* 定義一個睡眠的增強 同時實現前置 和后置
* @author 陳麗娜
* @version 2015年5月31日上午9:24:43
*/

public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice {

 
@Override
public void afterReturning(Object returnValue, Method method,Object[] args, Object target) throws Throwable {
   System.out.println("睡覺前要敷面膜");
}

 @Override
public void before(Method method, Object[] args, Object target)throws Throwable {
   System.out.println("睡覺后要做美夢");
}
}

 

1、基于代理的AOP

<!-- 創建一個增強 advice -->

       <bean id ="sleepHelper" class="com.tgb.springaop.aspect.SleepHelper"/>
       <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>
       <!-- 定義切點   匹配所有的sleep方法-->
       <bean id ="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
             <property name="pattern" value=".*sleep"></property>
       </bean>
     
       <!-- 切面 增強+切點結合 -->
       <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
            <property name="advice" ref="sleepHelper"/>
            <property name="pointcut" ref="sleepPointcut"/>
       </bean>      

       <!-- 定義代理對象 -->
       <bean id="linaProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
               <property name="target" ref="lina"/>
               <property name="interceptorNames" value="sleepHelperAdvisor"/>
       </bean>

 

如配置文件中:

pattern屬性指定了正則表達式,他匹配所有的sleep方法

使用org.springframework.aop.support.DefaultPointcutAdvisor的目的是為了使切點和增強結合起來形成一個完整的切面

最后配置完后通過org.springframework.aop.framework.ProxyFactoryBean產生一個最終的代理對象。

 

2、純簡單java對象切面

純簡單java對象切面這話怎么說呢,在我看來就是相對于第一種配置,不需要使用代理,,而是通過spring的內部機制去自動掃描,這時候我們的配置文件就該如下修改:

<!-- 創建一個增強 advice -->
       <bean id ="sleepHelper" class="com.tgb.springaop.aspect.SleepHelper"/>
       <!-- 目標類 -->
       <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>

       <!--  配置切點和通知-->
       <bean id ="sleepAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <property name="advice" ref="sleepHelper"></property>
            <property name="pattern" value=".*sleep"/>
       </bean>

       <!-- 自動代理配置 -->
       <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

是不是相對于第一種簡單了許多,不用再去配置代理了。

 

3、@Aspect注解形式

根據我們的經驗也知道,注解的形式相對于配置文件是簡單一些的,這時候需要在已有的方法或類上家注解:

/**
* 通過注解的方式 添加增強
* @author 陳麗娜
* @version 2015年5月31日上午10:26:13
*/

@Aspect
@Component
public class SleepHelper03 { 
/*@Pointcut("execution(* com.tgb.springaop.service.impl..*(..))")*/
@Pointcut("execution(* *.sleep(..))")
public void sleeppoint(){}

@Before("sleeppoint()")
public void beforeSleep(){
   System.out.println("睡覺前要敷面膜");
}

@AfterReturning("sleeppoint()")
public void afterSleep(){
   System.out.println("睡覺后要做美夢");
}

 

配置文件中只需寫:

<!--掃描包 -->
       <context:component-scan base-package="com.tgb" annotation-config="true"/> 
       <!-- ASPECTJ注解 -->
       <aop:aspectj-autoproxy  proxy-target-class="true" />  
      
       <!-- 目標類 -->
       <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>

 

4、注入形式的Aspcet切面

個人感覺這個是最簡單的也是最常用的,也是最靈活的。配置文件如下:

<!-- 目標類 -->
       <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>
       <bean id ="sleepHelper" class="com.tgb.springaop.aspect.SleepHelper02"/>
      
       <aop:config>
           <aop:aspect ref="sleepHelper">
                <aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))"/>
                <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))"/>
           </aop:aspect>
       </aop:config>

配置文件中提到的SleepHelper02類如下:

/**
* 通過注解的方式 添加增強
* @author 陳麗娜
* @version 2015年5月31日上午10:26:13
*/

public class SleepHelper02 {

public void beforeSleep(){
   System.out.println("睡覺前要敷面膜");
}

public void afterSleep(){
   System.out.println("睡覺后要做美夢");
}
}

 

參考:http://itindex.net/detail/53556-spring-aop


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 AutoPoster 的頭像
    AutoPoster

    互聯網 - 大數據

    AutoPoster 發表在 痞客邦 留言(0) 人氣()