Learn Spring - Spring AOP

1. 術語

  • 鏈接點(JointPoint):代碼中具備邊界性質特定點;Spring僅支持方法的鏈接點,包含方法和方位兩方面信息java

  • 切點(Pointcut):定位到某個方法spring

  • 加強(Advice):織入到目標鏈接點上的代碼數組

  • 目標對象(Target):加強邏輯的目標織入類ide

  • 引介(Introduction):特殊的加強,爲類添加一些屬性和方法函數

  • 織入(Weaving):將加強添加到目標鏈接點上的過程:編譯期織入、類裝載期織入、動態代理織入(Spring的方案)性能

  • 代理(Proxy):被AOP織入加強後的結果類測試

  • 切面(Aspect):切點+加強this

2. 動態代理的兩種實現:JDK和CGLib

  • JDK動態代理動態建立一個符合某一接口的實力,生成目標類的代理對象,缺點是須要提供接口;方法必須是publicpublic final代理

  • CGLib採用底層的字節碼技術,在子類中對父類的方法進行攔截,織入橫切邏輯;不能爲finalprivate方法代理code

  • 樣例

package test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ProxyTest {

    public static void main(String[] args) {
        ServiceImpl jdkTarget = new ServiceImpl();
        ProxyHandler handler = new ProxyHandler(jdkTarget);
        Service jdkProxy = (Service)Proxy.newProxyInstance(
            jdkTarget.getClass().getClassLoader(),
            jdkTarget.getClass().getInterfaces(),
            handler);
        jdkProxy.process("jdk proxy");

        System.out.println();

        CglibProxy cglibProxy = new CglibProxy();
        ServiceImpl cglibTarget = (ServiceImpl)cglibProxy.getProxy(ServiceImpl.class);
        cglibTarget.process("cglib proxy");
    }

    public interface Service {
        public void process(String arg);
    }

    public static class ServiceImpl implements Service {
        @Override
        public void process(String arg) {
            System.out.println("do something with " + arg);
        }
    }

    //jdk proxy
    public static class ProxyHandler implements InvocationHandler {
        private Object target;
        public ProxyHandler(Object target) {
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
            System.out.println("before process jdk proxy");
            Object obj = method.invoke(target, args);
            System.out.println("after process jdk proxy");
            return obj;
        }
    }

    //cglib proxy
    public static class CglibProxy implements MethodInterceptor {
        private Enhancer enhancer = new Enhancer();
        public Object getProxy(Class clazz) {
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("before process cglib proxy");
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("after process cglib proxy");
            return result;
        }
    }
}
  • 結果

before process jdk proxy
do something with jdk proxy
after process jdk proxy

before process cglib proxy
do something with cglib proxy
after process cglib proxy
  • 性能:CGLib所建立的動態代理對象性能比JDK方式高(約10倍),但CGLib在建立代理對象時所花費的時間比JDK方式多(約8倍);CGLib適合Spring裏singleton模式的bean管理

3. ProxyFactory

  • Spring定義了org.springframework.aop.framework.AopProxy接口及Cglib2AopProxyJdkDynamicAopProxy兩個final實現類

  • 若是經過ProxyFactorysetInterfaces(Class[] interfaces)指定針對接口代理,則使用JdkDynamicAopProxy;若是使用setOptimize(true),使用Cglib2AopProxy

  • ProxyFacotry經過addAdvice(Advice)造成加強鏈

4. 加強類型

4.1 前置加強

  • 接口:org.springframework.aop.BeforeAdvice

  • 樣例

package com.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2)
        throws Throwable {
        String arg = (String)arg1[0];
        System.out.println("before advice " + arg);
    }
}

4.2 後置加強

  • 接口:org.springframework.aop.AfterReturninigAdvice

  • 樣例

package com.aop;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class AfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        String arg = (String)args[0];
        System.out.println("after advice " + arg);
    }
}

4.3 環繞加強

  • 接口:org.aopalliance.intercept.MethodInterceptor

  • 樣例

package com.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        String arg = (String)args[0];
        System.out.println("around advice: before " + arg);
        Object obj = invocation.proceed();
        System.out.println("around advice: after " + arg);
        return obj;
    }
}

4.4 異常拋出加強

  • 接口:org.springframework.aop.ThrowsAdvice

  • 樣例

package com.aop;
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;

public class ExceptionAdvice implements ThrowsAdvice {
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
        throws Throwable {
        System.out.println("------");
        System.out.println("throws exception, method=" + method.getName());
        System.out.println("throws exception, message=" + ex.getMessage());
    }
}

4.5 測試

4.5.1 基於代碼的測試
  • TestAopAdvice

package com.aop;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;

public class TestAopAdvice {
    public static void main(String[] args) {
        AopExample example = new AopExample();
        BeforeAdvice beforeAdvice = new BeforeAdvice();
        AfterAdvice afterAdvice = new AfterAdvice();
        AroundAdvice aroundAdvice = new AroundAdvice();
        ThrowsAdvice throwsAdvice = new ExceptionAdvice();

        ProxyFactory pf = new ProxyFactory();
        pf.setTarget(example);
        pf.addAdvice(beforeAdvice);
        pf.addAdvice(afterAdvice);
        pf.addAdvice(aroundAdvice);
        pf.addAdvice(throwsAdvice);
        AopExample proxy = (AopExample)pf.getProxy();

        proxy.handle("blabla");
        System.out.println();

        try{
            proxy.throwExp("blabla");
        } catch(Exception e) {
        }
    }
}
  • 輸出

before advice blabla
around advice: before blabla
aop example blabla
around advice: after blabla
after advice blabla

before advice blabla
around advice: before blabla
----after throwing----
throws exception, method=throwExp
throws exception, message=try throws advice
4.5.2 基於Spring配置的測試
  • springAop.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="aopExample" class="com.aop.AopExample" />
    <bean id="beforeAdvice" class="com.aop.BeforeAdvice" />
    <bean id="afterAdvice" class="com.aop.AfterAdvice" />
    <bean id="aroundAdvice" class="com.aop.AroundAdvice" />
    <bean id="exceptionAdvice" class="com.aop.ExceptionAdvice" />
    <bean id="aopTest" class="org.springframework.aop.framework.ProxyFactoryBean"
        p:proxyTargetClass="true"
        p:interceptorNames="beforeAdvice,afterAdvice,aroundAdvice,exceptionAdvice"
        p:target-ref="aopExample" />
</beans>
  • TestAopAdvice2

package com.aop;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAopAdvice2 {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("/springAop.xml");
        AopExample aopExample = (AopExample)ctx.getBean("aopTest");
        aopExample.handle("blabla");
        System.out.println();
        try{
            aopExample.throwExp("blabla");
        } catch(Exception e) {
        }
        ctx.close();
    }
}
  • 輸出

二月 09, 2017 9:54:11 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 21:54:11 CST 2017]; root of context hierarchy
二月 09, 2017 9:54:11 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springAop.xml]
before advice blabla
around advice: before blabla
aop example blabla
around advice: after blabla
after advice blabla

before advice blabla
around advice: before blabla
----after throwing----
throws exception, method=throwExp
throws exception, message=try throws advice
二月 09, 2017 9:54:11 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 21:54:11 CST 2017]; root of context hierarchy

4.6 引介加強

  • 接口:org.springframework.aop.IntroductionInterceptor

4.6.1 基於Spring配置的測試代碼
  • IntroductionAdvice

package com.aop;

public interface IntroductionAdvice {
    public void setIntroductionActive(boolean active);
}
  • ConfigurableIntroduction

package com.aop;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;

public class ConfigurableIntroduction extends DelegatingIntroductionInterceptor implements IntroductionAdvice {

    private ThreadLocal<Boolean> map = new ThreadLocal<Boolean>();

    @Override
    public void setIntroductionActive(boolean active) {
        map.set(active);
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object obj = null;
        if(map.get() != null && map.get()) {
            System.out.println("before monitor operation");
            obj = super.invoke(invocation);
            System.out.println("after monitor operation");
        } else {
            obj = super.invoke(invocation);
        }
        return obj;
    }
}
  • TestIntroductionAdvice

package com.aop;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIntroductionAdvice {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("/springAop.xml");
        AopExample introductionAop = (AopExample)ctx.getBean("introductionAop");
        introductionAop.handle("introduction advice");
        IntroductionAdvice ci = (IntroductionAdvice)introductionAop;
        ci.setIntroductionActive(true);
        introductionAop.handle("introduction advice");
        ctx.close();
    }
}
  • springAop.xml添加

<bean id="configurableIntroduction" class="com.aop.ConfigurableIntroduction" />
<bean id="introductionAop" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interfaces="com.aop.IntroductionAdvice"
    p:target-ref="aopExample"
    p:interceptorNames="configurableIntroduction"
    p:proxyTargetClass="true" />
  • 輸出

二月 09, 2017 9:56:10 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 21:56:10 CST 2017]; root of context hierarchy
二月 09, 2017 9:56:10 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springAop.xml]
aop example introduction advice
----
before monitor operation
aop example introduction advice
after monitor operation
二月 09, 2017 9:56:11 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 21:56:10 CST 2017]; root of context hierarchy
4.6.2 與其餘加強在配置上的區別
  • 須指定引介加強所實現的接口

  • 只能經過爲目標類建立子類的方式生成引介加強的代理,所以proxyTargeClass必須爲true

5. Spring中的配置

參數說明

  • target:代理的對象

  • proxyInterfaces:代理所要實現的接口

  • interceptorNames:須要織入目標對象的bean列表,這些bean必須是實現了org.aopalliance.intercept.MethodInterceptororg.springframework.aop.Advisor的bean,配置中的順序對應調用的順序

  • singleton:返回的代理是否爲單例,默認爲true

  • optimize:爲true時使用CGLib代理

  • proxyTargetClass:爲true時使用CGLib代理,並覆蓋proxyInterfaces設置

6. Java註解

  • 一個例子

package com.aspectj;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Target(ElementType.METHOD) //聲明可使用該註解的目標類型
@Retention(RetentionPolicy.RUNTIME)//聲明註解的保留期限
public @interface Authority {
    boolean value() default true;//聲明註解成員
}
  • 成員以無入參無拋出異常的方式聲明

  • 能夠經過default爲成員指定一個默認值

  • 在方法上使用註解:@Authority(value=true)

  • 若是註解只有一個成員,需命名爲value(),使用時能夠忽略成員名和賦值號(=),如@Authority(true)

  • 註解類擁有多個成員時,若是僅對value成員賦值,能夠不適用賦值號;若是同時對多個成員賦值,則必須使用賦值號

  • 註解類能夠沒有成員,稱爲標識註解

  • 全部註解類隱式繼承於java.lang.annotation.Annotation,註解不容許顯式繼承於其餘接口

  • 若是成員是數組類型,能夠經過{}賦值

7. 基於AspectJ的AOP

7.1 一個例子

  • 定義切面

package com.aspectj;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class PreAspect {
    @Before("execution(*handle(..))")
    public void before() {
        System.out.println("aspect: before processing");
    }
}
  • 測試

package com.aspectj;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import com.aop.AopExample;

public class AspectJTest {
    public static void main(String[] args) {
        AspectJProxyFactory factory = new AspectJProxyFactory();
        AopExample example = new AopExample();
        factory.setTarget(example);
        factory.addAspect(PreAspect.class);
        AopExample proxy = factory.getProxy();
        proxy.handle("pre aspect");
    }
}
  • 結果

aspect: before processing
aop example pre aspect

7.2 經過配置使用切面

7.2.1 典型配置
  • springAspectj.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="aopExample" class="com.aop.AopExample" />
    <bean id="preAspect" class="com.aspectj.PreAspect" />
    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
</beans>
7.2.2 基於Schema的配置
  • springAspectj.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy />
    <bean id="aopExample" class="com.aop.AopExample" />
    <bean id="preAspect" class="com.aspectj.PreAspect" />
</beans>
  • AspectJTest2

package com.aspectj;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.aop.AopExample;

public class AspectJTest2 {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("/springAspectj.xml");
        AopExample aopExample = (AopExample)ctx.getBean("aopExample");
        aopExample.handle("blabla");
        ctx.close();
    }
}
  • 輸出

二月 09, 2017 10:13:56 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 22:13:56 CST 2017]; root of context hierarchy
二月 09, 2017 10:13:56 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springAspectj.xml]
aspect: before processing
aop example blabla
二月 09, 2017 10:13:57 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@69d0a921: startup date [Thu Feb 09 22:13:56 CST 2017]; root of context hierarchy
  • 經過<aop:aspectj-autoproxy />引入aop命名空間,自動爲Spring容器中匹配@AspectJ切面的bean建立代理,完成切面織入,其內部實現仍爲AnnotationAwareAspectJAutoProxyCreator

  • <aop:aspectj-autoproxy />proxy-target-class屬性爲false時,採用JDK動態代理;爲true時使用CGLib

8. AspectJ語法

8.1 切點表達式函數

  • 分類

類型 說明 舉例
方法切點函數 經過描述目標類方法信息定義鏈接點 execution()@annotation()
方法入參切點函數 經過描述目標類方法入參的信息定義鏈接點 args()@args()
目標類切點函數 經過描述目標類類型信息定義鏈接點 within()target()@within()@target()
代理類切點函數 經過描述目標類的代理類的信息定義鏈接點 this()
  • 函數說明

函數 入參 說明
execution() 方法匹配模式串 表示知足某一匹配模式的全部目標類方法鏈接點,如execution(* handle(..))表示全部目標類中的handle()方法
@annotation() 方法註解類名 表示標註了特定註解的目標方法鏈接點,如@annotation(com.aspectj.Authority)表示任何標註了@Authority註解的目標類方法
args() 類名 經過判別目標類方法運行時入參對象的類型定義指定鏈接點,如args(com.data.Car)表示全部有且僅有一個按類型匹配於Car(含子類)入參的方法
@args() 類型註解類名 經過判別目標方法運行時入參對象的類是否標註特定註解來制定鏈接點,如@args(com.aspectj.Authority)表示任何這樣的一個目標方法:它有一個入參且入參對象的類標註@Authority註解。要使@args()生效,類繼承樹中,標註註解的類類型須要不高於入參類類型
within 類名匹配串 表示特定域下的全部鏈接點,如within(com.service.*)within(com.service.*Service)within(com.service..*)
target() 類名 假如目標按類型匹配於指定類,則目標類的全部鏈接點匹配這個切點。如經過target(com.data.Car)定義的切點,CarCar的子類中的全部鏈接點都匹配該切點,包括子類中擴展的方法
@within() 類型註解類名 假如目標類按類型匹配於某個類A,且類A標註了特定註解,則目標類的全部鏈接點都匹配於這個切點。如@within(com.aspectj.Authority)定義的切點,假如Car類標註了@Authority註解,則Car以及Car的子類的全部鏈接點都匹配。@within標註接口類無效
@target() 類型註解類名 目標類標註了特定註解,則目標類(不包括子類)全部鏈接點都匹配該切點。如經過@target(com.aspectj.Authority)定義的切點,若BMWCar標註了@Authority,則BMWCar全部鏈接點匹配該切點
this() 類名 代理類按類型匹配於指定類,則被代理的目標類全部鏈接點匹配切點

8.2 通配符

8.2.1 通配符類型
類型 說明
* 匹配任意字符,但只能匹配上下文中的一個元素
.. 匹配任意字符,能夠匹配上下文中的多個元素。表示類時,和*聯合使用;表示入參時單獨使用
+ 按類型匹配指定類的全部類(包括實現類和繼承類),必須跟在類名後面
8.2.1 函數按通配符支持分類
  • 支持全部通配符:execution()within()

  • 僅支持+通配符:args()this()target()

  • 不支持通配符:@args@within@target@annotation

8.3 加強類型

  • @Before:前置加強,至關於BeforeAdvice

  • @AfterReturning:後置加強,至關於AfterReturningAdvice

  • @Around:環繞加強,至關於MethodInterceptor

  • @AfterThrowing:至關於ThrowsAdvice

  • @After:Final加強,拋出異常或正常退出都會執行的加強

  • @DeclareParents:引介加強,至關於IntroductionInterceptor

8.4 Execution()

  • 語法:execution(<修飾符模式>? <返回類型模式> <方法名模式> (<參數模式>) <異常模式>?)

8.4.1 經過方法簽名定義切點
  • execution(pulic * *(..)):匹配目標類的public方法,第一個*表明返回類型,第二個*表明方法名,..表明任意入參

  • execution(* *To(..)):匹配目標類全部以To結尾的方法,第一個*表明返回類型,*To表明任意以To結尾的方法

8.4.2 經過類定義切點
  • execution(* com.data.User.*(..)):匹配User接口的全部方法

  • execution(* com.data.User+.*(..)):匹配User接口的全部方法,包括其實現類中不在User接口中定義的方法

8.4.3 經過類包定義切點
  • execution(* com.data.*(..)):匹配data包下全部類的全部方法

  • execution(* com.data.User..*(..)):匹配data包及其子孫包中的全部類的全部方法

  • execution(* com..*Manager.get*(..)):匹配com包及其子孫包中後綴爲Manager的類裏以get開頭的方法

8.4.4 經過方法入參定義切點
  • execution(* get(String, int)):匹配get(String, int)方法

  • execution(* get(String, *)):匹配名爲get且第一個入參類型爲String、第二個入參類型任意的方法

  • execution(* get(String, ..)):匹配名爲get且第一個入參爲String類型的方法

  • execution(* get(Object+)):匹配名爲get且惟一入參是Object或其子類的方法

8.5 進階

8.5.1 邏輯運算符
  • &&,或||,非!

8.5.2 切點複合運算
  • 例如:@After("within(com.data.*) && execution(* handle(..))")

8.5.3 命名切點
  • 使用@Pointcut命名切點

  • 使用方法名做爲切點的名稱,方法的訪問控制符控制切點的可用性

@Pointcut("within(com.data.*)")
public void inPackage(){} //別名爲inPackage
8.5.4 加強織入的順序
  • 若是加強在同一個切面類中聲明,則依照加強在切面類中定義的順序織入

  • 若是加強位於不一樣的加強類中,且都實現了org.springframework.core.Ordered接口,則由接口方法的順序號決定(順序號小的先織入)

  • 若是加強位於不一樣的加強類中,且沒有實現org.springframework.core.Ordered接口,織入順序不肯定

8.5.5 訪問鏈接點信息
  • AspectJ使用org.aspectj.lang.JointPoint接口表示目標類鏈接點對象。若是是環繞加強時,使用org.aspectj.lang.ProceedingJointPoint表示鏈接點對象,該類是JointPoint接口的子接口。任何一個加強方法均可以經過將第一個入參聲明爲JointPoint訪問到鏈接點上下文的信息

8.5.6 綁定鏈接點方法入參
  • args()用於綁定鏈接點方法的入參,@annotation()用於綁定鏈接點方法的註解對象,@args()用於綁定鏈接點方法的入參註解。下例表示方法入參爲(String, int, ..)的方法匹配該切點,並將nameage兩個參數綁定到切面方法的入參中

@Before("args(name, age, ..)")
public void bindJointPointValues(String name, int age) {
    //do something
}
8.5.7 綁定代理對象
  • 使用this()target()能夠綁定被代理對象的實例。下例表示代理對象爲User類的全部方法匹配該切點,且代理對象綁定到user入參中

@Before("this(user)")
public void bindProxy(User user) {
    //do something
}
8.5.8 綁定類註解對象
  • @within()@target()函數能夠將目標類的註解對象綁定到加強方法中

@Before("@within(a)")
public void bindAnnotation(Authority a) {
    //do something
}
8.5.9 綁定返回值
  • 經過returning綁定鏈接點方法的返回值

@AfterReturning(value="target(com.data.Car)", returning="rvl")
public void bindReturningValue(int rvl) {
    //do something
}
  • rvl的類型必須和鏈接點方法的返回值類型匹配

8.5.10 綁定拋出的異常
  • 使用AfterThrowing註解的throwing成員綁定

@AfterThrowing(value="target(com.data.Car)", throwing="iae")
public void bindException(IllegalArgumentException iae) {
    //do something
}
相關文章
相關標籤/搜索