spring AOP

AOP概念java

 AOP即面向切面編程,指把不該該放在業務邏輯裏的橫切關注點抽取出來封裝到切面類的方法裏,當程序運行時再把這些橫切關注點織入到一個或多個鏈接點。正則表達式


AOP做用spring

業務邏輯並不知道切面的存在,也沒必要不用去關心切面,實現了業務邏輯和橫切關注點的分離編程


AOP術語 ide

橫切關注點是散佈應用多處的功能;橫切關注點在概念上應該與業務邏輯分離,但每每會直接嵌入到應用的業務邏輯中。性能

切面是抽取橫切關注點並封裝而造成的類。this

加強定義了切面是什麼及什麼時候使用。是什麼,是一段代碼;什麼時候使用,能夠是某個方法調用前、調用後、拋出異常後。spa

切點定義了哪些方法調用加強,切點只定義到某個方法上。3d

鏈接點由加強和切點共同定義,是使用加強的時機,即某個目標對象的某個方法調用以後、以前或拋出異常後插入加強的這個時間點;spring僅支持方法上的鏈接點。其它的AOP實現還支持其它的鏈接點,好比:類初始化前、類初始化後。代理

織入——在目標對象的生命週期裏有多個點能夠進行織入:
一、編譯期,切面在目標類編譯時被織入,須要特殊的Java編譯器。
二、類加載期,切面在目標類加載到JVM時被織入,須要特殊的類裝載器。
三、運行期,即動態代理織入,在運行期爲目標類添加加強生成子類。
spring採用動態代理織入,AspectJ採用編譯期織入或類加載期織入。

引入容許咱們向現有的類添加新方法或屬性。

代理,一個類被AOP織入加強後,就產生了一個結果類,它是融合了原類和加強邏輯的代理類。


spring AOP

Spring AOP使用動態代理在運行期把加強邏輯織入到目標對象。Spring AOP使用了兩種動態代理機制,一種是基於JDK的動態代理;一種是基於CGlib的動態代理。

package org.springframework.aop.framework;
public interface AopProxy {
    Object getProxy();

    Object getProxy(ClassLoader var1);
}
View Code
class CglibAopProxy implements AopProxy{}
View Code
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler{}
View Code

spring 加強

AOP聯盟的目的是定義標準的AOP規範,以便各類遵照標準的具體實現能夠相互調用

// 加強
public interface Advice {
}
public interface Interceptor extends Advice {
}
// 環繞加強
public interface MethodInterceptor extends Interceptor {
}
AOP聯盟接口
// 前置加強
public interface BeforeAdvice extends org.aopalliance.aop.Advice {
}
// spring只支持方法上的鏈接點,因此只有一個子接口MethodBeforeAdvice
public interface MethodBeforeAdvice extends BeforeAdvice {
}

// 後置加強,有兩個子接口,AfterReturningAdvice和ThrowsAdvice
public interface AfterAdvice extends org.aopalliance.aop.Advice {
}
public interface AfterReturningAdvice extends AfterAdvice {
}
public interface ThrowsAdvice extends AfterAdvice {
}

// 環繞加強,直接使用AOP聯盟定義的接口
public interface MethodInterceptor extends Interceptor {
}

// 引入加強
public interface DynamicIntroductionAdvice extends org.aopalliance.aop.Advice {
}
public interface IntroductionInterceptor 
extends org.aopalliance.intercept.MethodInterceptor, org.springframework.aop.DynamicIntroductionAdvice {
}
// 引入加強的實現類
public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport implements IntroductionInterceptor {
// 引入加強能夠爲目標類建立實現某接口的代理類,爲目標類添加方法和成員變量;
// 引入加強的鏈接點是類級別的,不是方法級別的。
}
spring接口 

demo1——前置加強

package com.test.spring;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

import java.lang.reflect.Method;

/**
 * 也能夠經過IOC配置spring的代理工廠
 */
public class Driver {
    public static void main(String[] args) {
        // 目標對象
        Tank tank = new Tank();
        // 切面類
        LogBeforeAdvice beforeAdvice = new LogBeforeAdvice();
        //  spring代理工廠
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(tank);
        proxyFactory.addAdvice(beforeAdvice);
        // 獲取代理對象
        Tank proxy = (Tank) proxyFactory.getProxy();
        proxy.run();
    }
}
class Tank {
    public void run() {
        System.out.println("run ...");
    }
}
class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    // method是目標類的方法;args是目標類方法參數;obj是目標類實例
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("begin ...");
    }
}
View Code
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
pom.xml

demo2——引入加強

package com.test.spring;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;

public interface Monitorable {
    void setMonitorActive(boolean active);
}
class MyDelegatingIntroductionInterceptor extends DelegatingIntroductionInterceptor implements Monitorable {
    private boolean monitorActive;
    @Override
    public void setMonitorActive(boolean active) {
        this.monitorActive = active;
    }
    public Object invoke(MethodInvocation mi) throws Throwable {
       Object obj = null;
       if (monitorActive) {
           System.out.println("begin ...");
           obj = super.invoke(mi);
       } else {
           obj = super.invoke(mi);
       }
       return null;
    }

}
class Tank {
    public void run() {
        System.out.println("run ...");
    }
}
class Driver {
    public static void main(String[] args) {
        // 引入加強
        MyDelegatingIntroductionInterceptor interceptor = new MyDelegatingIntroductionInterceptor();
        //  spring代理工廠
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new Tank());
        proxyFactory.addAdvice(interceptor);
        // 因爲引入加強必定經過CGLib生成子類,因此必須強制設置爲true,不然報錯
        proxyFactory.setProxyTargetClass(true);
        // 獲取代理對象
        Monitorable proxy = (Monitorable) proxyFactory.getProxy();
        Tank tank = (Tank) proxy;
        proxy.setMonitorActive(true);
        tank.run();

    }
}
View Code
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
pom.xml

spring 切點和切面 

因爲加強既包含橫切代碼,又包含鏈接點信息,如方法執行前、執行後,因此能夠僅經過加強類生成一個切面,如上面前置加強、引入加強的例子。但有一個問題,加強被織入到目標類的全部方法中了,這時須要使用切點。

切點僅表明目標類鏈接點的部分信息,即類和方法的定位,因此僅有切點沒法生成一個切面,必須結合加強才能生成切面。spring經過Pointcut接口描述切點,經過Advisor接口描述切面,切面包含加強和鏈接點信息。


spring切點

package org.springframework.aop;

public interface Pointcut {
    Pointcut TRUE = TruePointcut.INSTANCE;

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();
}

public interface ClassFilter {
    ClassFilter TRUE = TrueClassFilter.INSTANCE;
    // 匹配類
    boolean matches(Class<?> var1);
}

public interface MethodMatcher {
    MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
    // 匹配方法簽名
    boolean matches(Method var1, Class<?> var2);
    // 返回true,表示還要匹配入參;false,表示只匹配方法簽名
    boolean isRuntime();
    // 還要檢查實際的入參
    boolean matches(Method var1, Class<?> var2, Object... var3);
}
spring切點接口
spring提供了6種類型的切點
// 一、靜態方法切點,抽象類,默認匹配全部的類,有兩個實現類
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
    private ClassFilter classFilter;

    public StaticMethodMatcherPointcut() {
        this.classFilter = ClassFilter.TRUE;
    }

    public void setClassFilter(ClassFilter classFilter) {
        this.classFilter = classFilter;
    }

    public ClassFilter getClassFilter() {
        return this.classFilter;
    }

    public final MethodMatcher getMethodMatcher() {
        return this;
    }
}
// 簡單字符串匹配方法簽名
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {}
// 正則匹配方法簽名
public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {}

2、動態方法切點,抽象類,默認匹配全部類
public abstract class DynamicMethodMatcherPointcut extends DynamicMethodMatcher implements Pointcut {
    public DynamicMethodMatcherPointcut() {
    }

    public ClassFilter getClassFilter() {
        return ClassFilter.TRUE;
    }

    public final MethodMatcher getMethodMatcher() {
        return this;
    }
}

3、註解切點
public class AnnotationMatchingPointcut implements Pointcut {}

4、表達式切點
public interface ExpressionPointcut extends Pointcut {
}
spring切點實現

spring切面 

// 通常切面,鏈接點是目標類的全部方法,通常不會直接使用
public interface Advisor {
    // spring切面組合了AOP聯盟的Advice
    Advice getAdvice();

    boolean isPerInstance();
}

// 包含切點的切面,經過父類還包含加強
public interface PointcutAdvisor extends Advisor {
    // 組合了切點
    Pointcut getPointcut();
}

import org.aopalliance.intercept.MethodInterceptor;
// 引入切面
public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {
}
spring切面接口

包含切點的切面——PointcutAdvisor的實現 

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
// 最經常使用的切面;通常經過擴展該類能夠定義本身的切面
}

public class NameMatchMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor {
// 按方法名定義切點
}

public class RegexpMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor {
// 按正則表達式定義切點
}

public abstract class StaticMethodMatcherPointcutAdvisor extends StaticMethodMatcherPointcut implements PointcutAdvisor, Ordered, Serializable {
// 按method對象定義切點,默認匹配全部類
}

public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
// 按AspectJ表達式定義切點
}

public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
// 按AspectJ語法定義切點
}
spring切面實現 

demo1——StaticMethodMatcherPointcutAdvisor

package com.test.spring;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

/**
 * 也能夠經過IOC配置spring的代理工廠
 */
class Driver {
    public static void main(String[] args) {
        MyAdvisor myAdvisor = new MyAdvisor(); // 切面
        LogBeforeAdvice beforeAdvice = new LogBeforeAdvice(); // 前置加強
        myAdvisor.setAdvice(beforeAdvice); // 把加強添加到切面
        //  spring代理工廠
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.addAdvisor(myAdvisor); // 傳入切面
        proxyFactory.setProxyTargetClass(true); // 不使用JDK動態代理
        proxyFactory.setTarget(new Car()); // 傳入目標對象
        Car proxy = (Car) proxyFactory.getProxy(); // 獲取代理對象
        proxy.run();
        proxyFactory.setTarget(new Tank()); // 傳入目標對象
        Tank proxy2 = (Tank) proxyFactory.getProxy(); // 獲取代理對象
        proxy2.run();
    }
}
class Tank {
    public void run() { System.out.println("run ...");}
    public void stop() { System.out.println("stop ...");}
}
class Car {
    public void run() {
        System.out.println("car run ...");
    }
}
// 切面類
class MyAdvisor extends StaticMethodMatcherPointcutAdvisor {
    @Override
    // 必須實現
    public boolean matches(Method method, Class<?> aClass) {
        return "run".equals(method.getName());
    }
    // 能夠不實現,默認匹配全部類
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            @Override
            public boolean matches(Class<?> clazz) {
                // 匹配Tank類及其子類
                return Tank.class.isAssignableFrom(clazz) || Car.class.isAssignableFrom(clazz);
            }
        };
    }
}
// 加強類
class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    // method是目標類的方法;args是目標類方法參數;obj是目標類實例
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("begin ...");
    }
}
View Code
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
pom.xml

demo2——RegexpMethodPointcutAdvisor

package com.test.spring;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;

import java.lang.reflect.Method;

/**
 * 也能夠經過IOC配置spring的代理工廠
 */
class Driver {
    public static void main(String[] args) {
        // 這個切面類功能齊備,通常不須要擴展,直接拿來用就能夠了
        RegexpMethodPointcutAdvisor myAdvisor = new RegexpMethodPointcutAdvisor();
        LogBeforeAdvice beforeAdvice = new LogBeforeAdvice(); // 前置加強
        myAdvisor.setAdvice(beforeAdvice); // 把加強添加到切面
        myAdvisor.setPattern(".*run");// 匹配的是全限定方法名,即帶類名的方法名
        //  spring代理工廠
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.addAdvisor(myAdvisor); // 傳入切面
        proxyFactory.setProxyTargetClass(true); // 不使用JDK動態代理
        proxyFactory.setTarget(new Car()); // 傳入目標對象
        Car proxy = (Car) proxyFactory.getProxy(); // 獲取代理對象
        proxy.run();
        proxyFactory.setTarget(new Tank()); // 傳入目標對象
        Tank proxy2 = (Tank) proxyFactory.getProxy(); // 獲取代理對象
        proxy2.run();
    }
}
class Tank {
    public void run() { System.out.println("run ...");}
    public void stop() { System.out.println("stop ...");}
}
class Car {
    public void run() {
        System.out.println("car run ...");
    }
}
// 加強類
class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    // method是目標類的方法;args是目標類方法參數;obj是目標類實例
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("begin ...");
    }
}
View Code
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
pom.xml

demo3——動態切面

package com.test.spring;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;

import java.lang.reflect.Method;

/**
 * 也能夠經過IOC配置spring的代理工廠
 */
class Driver {
    public static void main(String[] args) {
        DefaultPointcutAdvisor myAdvisor = new DefaultPointcutAdvisor(); // 切面
        LogBeforeAdvice beforeAdvice = new LogBeforeAdvice(); // 前置加強
        myAdvisor.setAdvice(beforeAdvice); // 把加強添加到切面
        MyDynamicMethodMatcherPointcut myPointcut = new MyDynamicMethodMatcherPointcut(); // 切點
        myAdvisor.setPointcut(myPointcut); // 把切點添加到切面

        ProxyFactory proxyFactory = new ProxyFactory(); //  spring代理工廠
        proxyFactory.addAdvisor(myAdvisor); // 傳入切面
        proxyFactory.setProxyTargetClass(true); // 不使用JDK動態代理

        proxyFactory.setTarget(new Tank()); // 傳入目標對象
        Tank proxy2 = (Tank) proxyFactory.getProxy(); // 獲取代理對象
        proxy2.run("tank");
        proxy2.run("tank");
        proxy2.stop("tank");
        proxy2.stop("tank");

        Method[] methods = new Tank().getClass().getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}
class Tank {
    public void run(String name) { System.out.println(name + " run ...");}
    public void stop(String name) { System.out.println(name + " stop ...");}
}
// 加強類
class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    // method是目標類的方法;args是目標類方法參數;obj是目標類實例
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("begin ...");
    }
}
class MyDynamicMethodMatcherPointcut extends DynamicMethodMatcherPointcut {
    /** DynamicMethodMatcherPointcut類既有靜態檢查的方法,也有動態檢查的方法
     *  因爲動態檢查對性能影響很大,因此應當避免每次對目標類的各個方法進行動態檢查
     *
     *  spring採用這樣的機制:
     *  在建立代理時對目標類的每一個方法作靜態檢查
     *  若是方法不匹配,則運行時再也不作動態檢查
     *  若是方法匹配,運行時再作動態檢查
     */
    @Override
    // 惟一必須實現的方法
    public boolean matches(Method method, Class<?> aClass, Object... args) {
        System.out.println("作動態檢查");
        String name = (String)args[0];
        return name.equals("tank");
    }
//    @Override
//    public ClassFilter getClassFilter() {
//        return new ClassFilter() {
//            @Override
//            public boolean matches(Class<?> clazz) {
//                System.out.println("調用" + clazz.getName() + ".getClassFilter方法作靜態檢查");
//                return Tank.class.isAssignableFrom(clazz);
//            }
//        };
//    }
//    @Override
//    public boolean matches(Method method, Class<?> clazz) {
//        System.out.println("靜態檢查" + method.getName() + "方法");
//        return "run".equals(method.getName());
//    }
}
View Code
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
pom.xml
// 控制檯輸出分析
// 1.在建立代理時對目標類的每一個方法作靜態檢查
調用com.test.spring.Tank.getClassFilter方法作靜態檢查
靜態檢查run方法
調用com.test.spring.Tank.getClassFilter方法作靜態檢查
靜態檢查stop方法
調用com.test.spring.Tank.getClassFilter方法作靜態檢查
靜態檢查toString方法
調用com.test.spring.Tank.getClassFilter方法作靜態檢查
靜態檢查clone方法

// 2.第一次調用方法時,調用靜態檢查
調用com.test.spring.Tank.getClassFilter方法作靜態檢查
靜態檢查run方法
// 3.若是方法匹配,運行時再作動態檢查
作動態檢查
begin ...
tank run ...
// 4.第二次調用方法時,再也不作靜態檢查
// 5.作動態檢查
作動態檢查
begin ...
tank run ...
// 2.第一次調用方法時,調用靜態檢查
調用com.test.spring.Tank.getClassFilter方法作靜態檢查
靜態檢查stop方法
// 3.若是方法不匹配,運行時再也不作動態檢查(這裏再也不作動態檢查,提升了性能)
tank stop ...
// 4.第二次調用方法時,再也不作靜態檢查
tank stop ...

// 若是去掉靜態檢查方法,以下所示,調用每一個方法時都會作動態檢查
作動態檢查
begin ...
tank run ...
作動態檢查
begin ...
tank run ...
作動態檢查
begin ...
tank stop ...
作動態檢查
begin ...
tank stop ...



// 標類的全部方法,在建立代理時也並非對目標類的每一個方法作靜態檢查
public void com.test.spring.Tank.run(java.lang.String)
public void com.test.spring.Tank.stop(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
輸出分析

spring自動建立代理 

在前面的示例中,須要被代理的bean都須要使用一個ProxyFactory的Bean來配置,配置煩瑣;spring爲此提供了自動代理機制,讓容器自動生成代理,Spring使用BeanPostProcessor來完成這項工做。

BeanPostProcessor的實現有BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator。

一、BeanNameAutoProxyCreator的使用——爲一組特定名稱的bean自動建立代理實例:

package com.test.spring;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

@Configuration
class MyConfig {
    @Bean
    public Tank tank() { return new Tank();}
    @Bean
    public Car car() { return new Car();}
    @Bean
    public LogBeforeAdvice logBeforeAdvice() {return new LogBeforeAdvice();}
    @Bean
    public BeanNameAutoProxyCreator autoProxyCreator() {
        BeanNameAutoProxyCreator autoProxyCreator = new BeanNameAutoProxyCreator();
        // 爲一組特定名稱的bean自動建立代理實例
        autoProxyCreator.setBeanNames(new String[]{"tank", "car"});// 設置目標類
        autoProxyCreator.setInterceptorNames("logBeforeAdvice"); // 設置加強類
        autoProxyCreator.isOptimize(); // 強制使用CGLib
        return autoProxyCreator;
    }
}
/**
 * 也能夠經過IOC配置spring的代理工廠
 */
public class Driver {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        Tank tank = context.getBean(Tank.class);
        tank.stop();
        Car car = context.getBean(Car.class);
        car.run();
    }
}
class Tank {
    public void run() { System.out.println("run ...");}
    public void stop() { System.out.println("stop ...");}
}
class Car {
    public void run() { System.out.println("car run ...");}
}
// 加強類
class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    // method是目標類的方法;args是目標類方法參數;obj是目標類實例
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("begin ...");
    }
}
View Code
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
pom.xml

 二、DefaultAdvisorAutoProxyCreator的使用——掃描容器中的切面Advisor,並將切面自動織入匹配的bean,並建立代理

package com.test.spring;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

@Configuration
class MyConfig {
    @Bean
    public Tank tank() { return new Tank();}
    @Bean
    public Car car() { return new Car();}
    @Bean
    public LogBeforeAdvice logBeforeAdvice() {return new LogBeforeAdvice();}
    @Bean
    public RegexpMethodPointcutAdvisor regexpMethodPointcutAdvisor(LogBeforeAdvice logBeforeAdvice) {
        RegexpMethodPointcutAdvisor myAdvisor = new RegexpMethodPointcutAdvisor();
        myAdvisor.setAdvice(logBeforeAdvice); // 把加強添加到切面
        myAdvisor.setPattern(".*run");// 匹配的是全限定方法名,即帶類名的方法名
        return myAdvisor;
    }
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
}
/**
 * 也能夠經過IOC配置spring的代理工廠
 */
public class Driver {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        Tank tank = context.getBean(Tank.class);
        tank.stop();
        Car car = context.getBean(Car.class);
        car.run();
    }
}
class Tank {
    public void run() { System.out.println("run ...");}
    public void stop() { System.out.println("stop ...");}
}
class Car {
    public void run() { System.out.println("car run ...");}
}
// 加強類
class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    // method是目標類的方法;args是目標類方法參數;obj是目標類實例
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("begin ...");
    }
}
View Code
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
View Code

spring 註解方式建立代理

demo1——使用工廠類AspectJProxyFactory 

package com.test.spring;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;

@Aspect
// 切面類必須爲public的
public class MyAdvice {
    @Before("execution(* com.test.spring.Car.*(..))")
    public void before() {
        System.out.println("begin ...");
    }
}
class Car {
    public void run() { System.out.println("car run ...");}
}

class MyTest {
    public static void main(String[] args) {
        AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
        proxyFactory.setTarget(new Car());
        proxyFactory.addAspect(MyAdvice.class);
        Car proxy = (Car)proxyFactory.getProxy();
        proxy.run();
    }
}
View Code
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.7.4</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.7.4</version>
    </dependency>
pom.xml

 demo2——使用BeanPostProcessor的實現類AnnotationAwareAspectJAutoProxyCreator自動掃描切面類,並織入到目標類

package com.test.spring;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Aspect
// 切面類必須爲public的
public class MyAdvice {
    @Before("execution(* com.test.spring.Car.*(..))")
    public void before() {
        System.out.println("begin ...");
    }
}
class Car {
    public void run() { System.out.println("car run ...");}
}
@Configuration
class MyConfig {
    @Bean
    public Car car() { return new Car(); }
    @Bean
    public MyAdvice myAdvice() { return new MyAdvice(); }
    @Bean
    public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
        return new AnnotationAwareAspectJAutoProxyCreator();
    }
}
class MyTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        Car proxy = context.getBean(Car.class);
        proxy.run();
        context.close();
    }
}
View Code
 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.7.4</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.7.4</version>
    </dependency>
pom.xml

 demo3——使用註解EnableAspectJAutoProxy

在spring內部依舊採用AnnotationAwareAspectJAutoProxyCreator自動建立代理。
註解EnableAspectJAutoProxy有一個proxyTargetClass能夠賦值爲布爾值,若是爲true,表示使用CGLib;默認爲fasle;不過即便設置爲false,若是目標類沒有實現接口,自動使用CGLib。

package com.test.spring;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

class Car {
    public void run() { System.out.println("car run ...");}
}
@Aspect
class MyAdvice {
    @Before("execution(* com.test.spring.Car.*(..))")
    public void before() {
        System.out.println("begin ...");
    }
}
@Configuration
@EnableAspectJAutoProxy
class MyConfig {
    @Bean
    public Car car() {
        return new Car();
    }
    @Bean
    public MyAdvice myAdvice() {
        return new MyAdvice();
    }
}
class MyTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        Car car = context.getBean(Car.class);
        car.run();
        context.close();
    }
}
View Code
 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.7.4</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.7.4</version>
    </dependency>
View Code

demo4——引入加強

package com.test.spring;

public interface Moveable {
    public void stop();
}
class Car { // Car類並無實現Moveable接口
    public void run() {
        System.out.println("car run ...");
    }
}
View Code
package com.test.spring;
// 實現類必須是public的,不然報錯
public class MoveableImpl implements Moveable{
    @Override
    public void stop() { System.out.println("car stop ..."); }
}
View Code
package com.test.spring;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Aspect
class MyAdvice {
    // value參數必須是類的全限定名
    @DeclareParents(value = "com.test.spring.Car", defaultImpl =MoveableImpl.class)
    public Moveable moveable;
}
@Configuration
@EnableAspectJAutoProxy()
class MyConfig {
    @Bean
    public Car car() { return new Car(); }
    @Bean
    public MyAdvice myAdvice() { return new MyAdvice(); }
}
class MyTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        Car car = context.getBean(Car.class);
        car.run();
        Moveable moveable = (Moveable)car;
        moveable.stop();
        context.close();
    }
}
View Code
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.7.4</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.7.4</version>
    </dependency>
View Code
相關文章
相關標籤/搜索