Spring AOP @AspectJ 入门基础

须要的类包:java

 

一、一个简单的例子spring

Waiter接口:
package com.yyq.annotation;
public interface Waiter {
    void greetTo(String name);
    void serveTo(String name);
}

NaiveWaiter业务类:数组

package com.yyq.annotation;
public class NaiveWaiter implements Waiter {
    @Override
    public void greetTo(String name) {
        System.out.println("NaiveWaiter:greet to " + name + "...");
    }
    @Override
    public void serveTo(String name) {
        System.out.println("NaiveWaiter:serving to " + name + "...");
    }
}

PreGreetingAspect切面实现类:ide

package com.yyq.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//经过该注解将PreGreetingAspect标识为一个切面
@Aspect
public class PreGreetingAspect {
    //定义切点和加强类型
    @Before("execution(* greetTo(..))")
    //加强的横切逻辑
    public void beforeGreeting(){
        System.out.println("How are you");
    }
}

测试方法:函数

@Test
    public void aspectJProxyTest(){
        Waiter target = new NaiveWaiter();
        AspectJProxyFactory factory = new AspectJProxyFactory();
        //设置目标对象
        factory.setTarget(target);
        //添加切面对象
        factory.addAspect(PreGreetingAspect.class);
        //生成织入切面的代理对象
        Waiter proxy = factory.getProxy();
        proxy.greetTo("Anny");
        proxy.serveTo("Mei");
    }

输出结果:测试

How are you
NaiveWaiter:greet to Anny...
NaiveWaiter:serving to Mei...
 
经过Spring配置使用@AspectJ切面:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!--目标Bean-->
    <bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/>
    <!--使用了@AspectJ注解的切面类-->
    <bean class="com.yyq.annotation.PreGreetingAspect"/>
    <!--自动代理建立器,自动将@AspectJ注解切面类织入到目标Bean中-->
    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
</beans>

测试方法:this

@Test
    public void aspectJProxyTest2(){
        String configPath = "com\\yyq\\annotation\\beans.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        Waiter waiter = (Waiter)ctx.getBean("waiter");
        waiter.greetTo("John");
    }
输出结果:
How are you
NaiveWaiter:greet to John...
 
使用基于Schema的AOP命名空间配置:
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/>
    <bean class="com.yyq.annotation.PreGreetingAspect"/>
</beans>

 测试方法:spa

  @Test
    public void aspectJProxyTest3(){
        String configPath = "com\\yyq\\annotation\\beans2.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        Waiter waiter = (Waiter)ctx.getBean("waiter");
        waiter.greetTo("Herry");
    }
输出结果:
How are you
NaiveWaiter:greet to Herry...
 
二、@AspectJ基础
    1)切点表达式函数
    AspectJ 5的切点表达式由关键字和操做参数组成,如execution(* greetTo(..))的切点表达式,“execute”为关键字,而“* greetTo(..)”为操做参数。在这里,execute表明目标类执行某一方法,而“* greetTo(..)”是描述目标方法的匹配模式串,二者联合起来所表示的切点匹配目标类greetTo()方法的链接点。为了描述方便,咱们将 execution()称做函数,而将匹配串“* greetTo(..)”称做函数的入参。 

    Spring支持9个@ApsectJ切点表达式函数,它们用不一样的方式描述目标类的链接点,根据描述对象的不一样,能够将它们大体分为4种类型: 
        · 方法切点函数:经过描述目标类方法信息定义链接点; 
        · 方法入参切点函数:经过描述目标类方法入参的信息定义链接点; 
        · 目标类切点函数:经过描述目标类类型信息定义链接点; 
        · 代理类切点函数:经过描述目标类的代理类的信息定义链接点; 代理

类别 函数 入参 说明
方法切点函数 execution() 方法匹配模式串 表示知足某一匹配模式的全部目标类方法链接点。如execution(* greetTo(..))表示全部目标类中的greetTo()方法。
@annotation() 方法注解类名 表示标注了特定注解的目标方法链接点。如@annotation(com.baobaotao.anno.NeedTest)表示任何标注了@NeedTest注解的目标类方法。
方法入参切点函数 args() 类名 经过判别目标类方法运行时入参对象的类型定义指定链接点。如args(com.baobaotao.Waiter)表示全部有且仅有一个按类型匹配于Waiter的入参的方法。
@args() 类型注解类名 经过判别目标方法的运行时入参对象的类是否标注特定注解来指定链接点。如@args(com.baobaotao.Monitorable)表示任何这样的一个目标方法:它有一个入参且入参对象的类标注@Monitorable注解。
目标类切点函数 within() 类名匹配串 表示特定域下的全部链接点。如within(com.baobaotao.service.*)表示 com.baobaotao.service包中的全部链接点,也即包中全部类的全部方法,而 within(com.baobaotao.service.*Service)表示在com.baobaotao.service包中,全部以 Service结尾的类的全部链接点。
target() 类名 假如目标类按类型匹配于指定类,则目标类的全部链接点匹配这个切点。如经过target(com.baobaotao.Waiter)定义的切点,Waiter、以及Waiter实现类NaiveWaiter中全部链接点都匹配该切点。
@within() 类型注解类名 假如目标类按类型匹配于某个类A,且类A标注了特定注解,则目标类的全部链接点匹配这个切点。如@within(com.baobaotao.Monitorable)定义的切点,假如Waiter类标注了@Monitorable注解,则Waiter以及Waiter实现类NaiveWaiter类的全部链接点都匹配。
@target() 类型注解类名 目标类标注了特定注解,则目标类全部链接点匹配该切点。如@target(com.baobaotao.Monitorable),假如NaiveWaiter标注了@Monitorable,则NaiveWaiter全部链接点匹配切点。
代理类切点函数 this() 类名 代理类按类型匹配于指定类,则被代理的目标类全部链接点匹配切点。

 

    2)在函数入参中使用通配符
    @AspectJ支持3种通配符:
  •  * 匹配任意字符,但它只能匹配上下文中的一个元素;   
  •  .. 匹配任意字符,能够匹配上下文中的多个元素,但在表示时,必须和 * 联合使用,而在表示入参时则单独使用;
  •  + 表示按类型匹配指定类的全部类,必须跟在类名后面,如com.yyq.Car+。继承或扩展指定类的全部类,同时还包括指定类自己。
    @AspectJ函数按其是否支持通配符及支持的程度,能够分为如下3类:
  • 支持全部通配符:execution()、within(),如within(com.yyq.*)、within(com.yyq.service..*.*Service+)等;
  • 仅支持 + 通配符:args()、this()、target(),如args(com.yyq.Waiter+)、target(java.util.List+)等。虽然这3个函数能够支持+通配符,但其意义不大,由于对于这些函数来讲使用和不使用+都是同样的,如target(com.yyq.Waiter+)和target(com.yyq.Waiter)是等价的。
  • 不支持通配符:@args()、@within()、@target()和@annotation(),如@args(com.yyq.anno.NeedTest)和@within(com.yyq.anno.NeedTest)。
    此外,args()、this()、target()、@args()、@within()、@target()和@annotation()这7个函数除了能够指定类名外,也能够指定变量名,并将目标对象中的变量绑定到加强的方法中。
 
    3)逻辑运算符
    切点表达式由切点函数组成,切点函数之间还能够进行逻辑运算,组成复合切点,Spring支持如下的切点运算符:
  • && 与操做符,至关于切点的交集运算,and是等效的操做符。如within(com.yyq..*) and args(String) 表示在com.yyq包下全部类(当前包以及子孙包)拥有一个String入参的方法;
  • ||  或操做符,至关于切点的并集运算,or是等效的操做符。如within(com.yyq..*) || args(String) 表示在com.yyq包下的全部类的方法,或者全部拥有一个String入参的方法;
  • ! 非操做符,至关于切点的反集运算,not是等效的操做符。如!within(com.yyq.*) 表示全部不在com.yyq包下的方法。
 
    4)不一样加强类型
    @AspectJ为各类的加强类型提供了不一样的注解类,它们位于org.aspectj.lang.annotation.*包中,这些注解类拥有若干个成员,能够经过这些成员完成定义切点信息、绑定链接点参数等操做;此外,这些注解的存留期限都是RetentionPolicy.RUNTIME,标注目标都是ElementType.METHOD。
  • @Before
        前置加强,至关于BeforeAdvice的功能,Before注解类拥有两个成员:
    • value:该成员用于定义切点;
    • argNames:因为没法经过Java反射机制获取方法入参名,全部若是在Java编译时未启动调试信息或者须要在运行期解析切点,就必须经过这个成员指定注解所标注加强方法的参数名(注意二者名字必须彻底相同),多个参数名用逗号分隔。
  • AfterReturning
        后置加强,至关于AfterReturningAdvice,AfterReturning注解类拥有4个成员:
    • value:该成员用于定义切点;
    • pointcut:表示切点的信息,若是显式指定pointcut值,它将覆盖value的设置值,能够将pointcut成员当作是value的同义词;
    • returning:将目标对象方法的返回值绑定给加强的方法;
    • argNames:如前所述。
  • Around
        环绕加强,至关于MethodInterceptor,Around注解类拥有两个成员:
    • value:该成员用于定义切点;
    • argNames:如前所述。
  • AfterThrowing
        抛出加强,至关于ThrowsAdvice,AfterThrowing注解类拥有4个成员:
    • value:该成员用于定义切点;
    • pointcut:表示切点的信息,若是显式指定pointcut值,它将覆盖value的设置值,能够将pointcut成员当作是value的同义词;
    • throwing:将抛出的异常绑定到加强方法中;
    • argNames:如前所述。
  • After
        Final加强,不论是抛出异常或者是正常退出,该加强都会获得执行,该加强没有对应的加强接口,能够把它当作是ThrowsAdvice和AfterReturningAdvice的混合物,通常用于释放资源,至关于try{}finally{}的控制流。After注解类拥有两个成员:
    • value:该成员用于定义切点;
    • argNames:如前所述。
  • DeclareParents
        引介加强,至关于IntroductionInterceptor,DeclareParents注解类拥有两个成员:
    • value:该成员用于定义切点,它表示在哪一个目标类上添加引介加强;
    • defaultImpl:默认的接口实现类。
     5)引介加强用法
    假设但愿NaiveWaiter可以同时充当售货员的角色,即经过切面技术为NaiveWaiter新增Seller接口的实现。
Seller接口:
package com.yyq.annotation;
public interface Seller {
  int sell(String goods, String clientName);
}

SmartSeller实现类:调试

package com.yyq.annotation;
public class SmartSeller implements Seller {
    public int sell(String goods,String clientName) {
        System.out.println("SmartSeller: sell "+goods +" to "+clientName+"...");
        return 100;
    }
}

EnableSellerAspect切面实现类:

package com.yyq.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class EnableSellerAspect {
    @DeclareParents(value = "com.yyq.annotation.NaiveWaiter",defaultImpl = SmartSeller.class)
    public Seller seller;
}

beans3.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/>
    <bean class="com.yyq.annotation.EnableSellerAspect"/>
</beans>

测试方法:

@Test
    public void aspectJProxyTest4(){
        String configPath = "com\\yyq\\annotation\\beans3.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        Waiter waiter = (Waiter)ctx.getBean("waiter");
        waiter.greetTo("John");
        Seller seller = (Seller)waiter;   //成功进行强制类型转换
        seller.sell("Beer","John");
    }
输出结果:
NaiveWaiter:greet to John...
SmartSeller: sell Beer to John...
 
三、切点函数详解
    1)@annotation()
    @annotation() 表示标注了某个注解的全部方法。
NeedTest标注类:
package com.yyq.aspectJ;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NeedTest {
    boolean value() default true;
}

 Waiter接口:

package com.yyq.aspectJ;
public interface Waiter {
    void greetTo(String name);
    void serveTo(String name);
}

NaiveWaiter实现类:

package com.yyq.aspectJ;
public class NaiveWaiter implements Waiter {
    @Override
    public void greetTo(String name) {
        System.out.println("NaiveWaiter:greet to " + name + "...");
    }
    @Override
    public void serveTo(String name) {
        System.out.println("NaiveWaiter:serving to " + name + "...");
    }
}

NaughtyWaiter实现类:

package com.yyq.aspectJ;
public class NaughtyWaiter implements Waiter {
    @NeedTest
    public void greetTo(String clientName) {
        System.out.println("NaughtyWaiter:greet to "+clientName+"...");
    }    
    public void serveTo(String clientName){
        System.out.println("NaughtyWaiter:serving "+clientName+"...");
    }
    public void joke(String clientName,int times){
            System.out.println("NaughtyWaiter:play "+times+" jokes to "+clientName+"...");
    }
}

TestAspcet切面实现类:

package com.yyq.aspectJ;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class TestAspect {
    @AfterReturning("@annotation(com.yyq.aspectJ.NeedTest)")
    public void needTestFun(){
        System.out.println("needTestFun() executed!");
    }
}

Spring配置自动应用切面:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="naiveWaiter" class="com.yyq.aspectJ.NaiveWaiter"/>
    <bean id="naughtyWaiter" class="com.yyq.aspectJ.NaughtyWaiter"/>
    <bean class="com.yyq.aspectJ.TestAspect"/>
</beans>

测试方法:

package com.yyq;
import com.yyq.aspectJ.Waiter;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AspectJTest {
    @Test
    public void annotationAspectJTest() {
        String configPath = "com\\yyq\\aspectJ\\beans.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        Waiter naiveWaiter = (Waiter) ctx.getBean("naiveWaiter");
        Waiter naughtyWaiter = (Waiter) ctx.getBean("naughtyWaiter");
        naiveWaiter.greetTo("John");
        naiveWaiter.serveTo("John");
        naughtyWaiter.greetTo("Tom");
        naughtyWaiter.serveTo("Tom");
    }
}
输出结果:
NaiveWaiter:greet to John...
NaiveWaiter:serving to John...
NaughtyWaiter:greet to Tom...
needTestFun() executed!
NaughtyWaiter:serving Tom...
 
    2)execution()
        execution()是最经常使用的切点函数,其语法以下所示:
        execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)
         除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。
  • 经过方法签名定义切点  
            · execution(public * *(..)) 
                匹配全部目标类的public方法,但不匹配SmartSeller和protected void showGoods()方法。第一个*表明返回类型,第二个*表明方法名,而..表明任意入参的方法;         
            · execution(* *To(..)) 
                匹配目标类全部以To为后缀的方法。它匹配NaiveWaiter和NaughtyWaiter的greetTo()和serveTo()方法。第一个*表明返回类型,而*To表明任意以To为后缀的方法; 
  • 经过类定义切点 
             · execution(* com.baobaotao.Waiter.*(..)) 
                匹配Waiter接口的全部方法,它匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo()方法。第一个*表明返回任意类型,com.baobaotao.Waiter.*表明Waiter接口中的全部方法; 
            · execution(* com.baobaotao.Waiter+.*(..)) 
                匹配Waiter接口及其全部实现类的方法,它不但匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo()这两个Waiter接口定义的方法,同时还匹配NaiveWaiter#smile()和NaughtyWaiter#joke()这两个不在Waiter 接口中定义的方法。
  • 经过类包定义切点
        在类名模式串中,“.*”表示包下的全部类,而“..*”表示包、子孙包下的全部类。 
            · execution(* com.baobaotao.*(..)) 
                匹配com.baobaotao包下全部类的全部方法; 
            · execution(* com.baobaotao..*(..)) 
                匹配com.baobaotao包、子孙包下全部类的全部方法,如com.baobaotao.dao,com.baobaotao.servier以及 com.baobaotao.dao.user包下的全部类的全部方法都匹配。“..”出如今类名中时,后面必须跟“*”,表示包、子孙包下的全部类; 
            · execution(* com..*.*Dao.find*(..)) 
                匹配包名前缀为com的任何包下类名后缀为Dao的方法,方法名必须以find为前缀。如com.baobaotao.UserDao#findByUserId()、com.baobaotao.dao.ForumDao#findById()的方法都匹配切点。 
  • 经过方法入参定义切点 
        切点表达式中方法入参部分比较复杂,可使用“*”和“ ..”通配符,其中“*”表示任意类型的参数,而“..”表示任意类型参数且参数个数不限。 
            · execution(* joke(String,int))) 
                匹配joke(String,int)方法,且joke()方法的第一个入参是String,第二个入参是int。它匹配 NaughtyWaiter#joke(String,int)方法。若是方法中的入参类型是java.lang包下的类,能够直接使用类名,不然必须使用全限定类名,如joke(java.util.List,int); 
            · execution(* joke(String,*))) 
                匹配目标类中的joke()方法,该方法第一个入参为String,第二个入参能够是任意类型,如joke(String s1,String s2)和joke(String s1,double d2)都匹配,但joke(String s1,double d2,String s3)则不匹配;
            · execution(* joke(String,..))) 
                匹配目标类中的joke()方法,该方法第 一个入参为String,后面能够有任意个入参且入参类型不限,如joke(String s1)、joke(String s1,String s2)和joke(String s1,double d2,String s3)都匹配;
            · execution(* joke(Object+))) 
                匹配目标类中的joke()方法,方法拥有一个入参,且入参是Object类型或该类的子类。 它匹配joke(String s1)和joke(Client c)。若是咱们定义的切点是execution(* joke(Object)),则只匹配joke(Object object)而不匹配joke(String cc)或joke(Client c)。
 
    3)args()和@args()
        args()函数的入参是类名,@args()函数的入参必须是注解类的类名。虽然args()容许在类名后使用+通配符后缀,但该通配符在此处没有意义:添加和不添加效果都同样。 
  • args()        
        该函数接受一个类名,表示目标类方法入参对象按类型匹配于指定类时,切点匹配。如:args(com.baobaotao.Waiter) 
        表示运行时入参是Waiter类型的方法,它和execution(* *(com.baobaotao.Waiter))区别在于后者是针对 类方法的签名而言的,而前者则针对 运行时的入参类型而言。如 args(com.baobaotao.Waiter)既匹配于addWaiter(Waiter waiter),也匹配于addNaiveWaiter(NaiveWaiter naiveWaiter),而execution(* *(com.baobaotao.Waiter))只匹配addWaiter(Waiter waiter)方法。实际上,args(com.baobaotao.Waiter)等价于execution(* *(com.baobaotao.Waiter+)),固然也等价于args(com.baobaotao.Waiter+)。
  • @args()
        该函数接受一个注解类的类名,当方法的运行时入参对象标注发指定的注解时,方法匹配切点。若是在类继承树中注解点@M高于入参类型点fun(T1 t),则该目标方法不可能匹配切点@args(M);若是在类继承树中注解点@M低于入参类型点fun(T1 t),则注解点所在类及其子孙类做为方法入参时,该方法匹配@args(M)切点。
        假设咱们定义这样的切点:@args(com.baobaotao.Monitorable) ,若是NaiveWaiter标注了@Monitorable,则对于WaiterManager#addWaiter(Waiter w)方法来讲,若是入参是NaiveWaiter或其子类对象,该方法匹配切点,若是入参是NaughtyWaiter对象,不匹配切点。若是 Waiter标注了@Monitorable,但NaiveWaiter未标注@Monitorable,则 WaiterManager#addNaiveWaiter(NaiveWaiter w)却不匹配切点,这是由于注解点(在Waiter)高于入参类型点(NaiveWaiter)。 
 
    4)within()
        经过类匹配模式串声明切点,within()函数定义的链接点是针对 目标类而言,而 非针对运行期对象的类型而言,这一点和execetion()是相同 的。但和execution()函数不一样的是,within()所指定的链接点最小范围只能是类,而execution()所指定的链接点,能够大到包, 小到方法入参。因此从某种意义上说,execution()函数的功能涵盖了within()函数的功能。within()函数的语法: within(<类匹配模式>) 

        形如within(com.baobaotao.NaiveWaiter)是within()函数所能表达的最小粒度,若是试图用within()匹配方法级别的链接点,如within(com.baobaotao.NaiveWaiter.greet*)将会产生解析错误。  

  • within(com.baobaotao.NaiveWaiter) 

        匹配目标类NaiveWaiter的全部方法。若是切点调整为within(com.baobaotao.Waiter),则NaiveWaiter和 NaughtyWaiter中的全部方法都不匹配,而Waiter自己是接口不可能实例化,因此 within(com.baobaotao.Waiter)的声明是无心义的; 

  • within(com.baobaotao.*) 

        匹配com.baobaotao包中的全部类,但不包括子孙包,因此com.baobaotao.service包中类的方法不匹配这个切点; 

  • within(com.baobaotao..*) 

        匹配com.baobaotao包及子孙包中的类,因此com.baobaotao.service、com.baobaotao.dao以及com.baobaotao.service.fourm等包中全部类的方法都匹配这个切点。

 
    5)@within()和@target()
        除 @annotation()和@args()外,还有另外两个用于注解的切点函数,它们分别是@target()和@within(),和 @annotation()及@args()函数同样,它们也只接受注解类名做为入参。其中@target(M)匹配任意标注了@M的目标类,而 @within(M)匹配标注了@M的类及子孙类。 
        假设NaiveWaiter标注了@Monitorable,则其子类CuteNaiveWaiter没有标注@Monitorable,则 @target(com.baobaotao.Monitorable)匹配NaiveWaiter类的全部方法,但不匹配 CuteNaiveWaiter类的方法。 
        假设NaiveWaiter标注了@Monitorable,而其子类CuteNaiveWaiter没有标注@Monitorable,则 @within(com.baobaotao.Monitorable)不但匹配NaiveWaiter类中的全部方法也匹配 CuteNaiveWaiter类中的全部方法。
        但有一个特别值得注意地方是,若是标注@M注解的是一个接口,则全部实现该接口的类并不 匹配@within(M)。假设Waiter标注了@Monitorable注解,但NaiveWaiter、NaughtyWaiter及 CuteNaiveWaiter这些接口实现类都没有标注@Monitorable,则 @within(com.baobaotao.Monitorable)和@target(com.baobaotao.Monitorable)都不匹 配NaiveWaiter、NaughtyWaiter及CuteNaiveWaiter。这是由于@within()、@target()以及 @annotation()都是针对目标类而言,而非针对运行时的引用类型而言,这点区别须要在开发中特别注意。

    6)target()和this()
        target()切点函数经过判断目标类是否按类型匹配指定类决定链接点是否匹配,而this()则经过判断代理类是否按类型匹配指定类来决定是否和切点 匹配。二者都仅接受类名的入参,虽然类名能够带“+”通配符,但对于这两个函数来讲,使用与不使用+通配符,效果彻底相同。
  • target() 
        target(M)表示若是目标类按类型匹配于M,则目标类全部方法匹配切点。
        · target(com.baobaotao.Waiter) 
            NaiveWaiter、NaughtyWaiter以及CuteNaiveWaiter的全部方法都匹配切点,包括那些未在Waiter接口中定义的方法,如NaiveWaiter#simle()和NaughtyWaiter#joke()方法。 
        · target(com.baobaotao.Waiter+) 
            和target(com.baobaotao.Waiter)是等价的。 
  • this()
        根据Spring的官方文档,this()函数判断代理对象的类是否按类型匹配于指定类,若是匹配,则代理对象的全部链接点匹配切点。但经过实验,咱们发现实际状况和文档有出入,如咱们声明一个this(com.baobaotao.NaiveWaiter)的切点,若是不使用CGLib代理,则生成的代理对象是Waiter类型,而非NaiveWaiter类型,这一点能够简单地经过instanceof操做符进行判断。可是,咱们发现 NaiveWaiter中全部的方法仍是被织入了加强。 
        在通常状况下,使用this()和target()经过定义切点,二者是等效的: 
        · target(com.baobaotao.Waiter) 等价于this(com.baobaotao.Waiter) 
        · target(com.baobaotao.NaiveWaiter) 等价于 this(com.baobaotao.NaiveWaiter) 
        二者区别体如今经过引介切面产生的代理对象时的具体表现,若是咱们经过本文前面的方法为NaiveWaiter引介一个Seller接口的实现,则 this(com.baobaotao.Seller)匹配NaiveWaiter代理对象的全部方法,包括NaiverWaiter自己的 greetTo()、serverTo()方法以及经过Seller接口引入的sell()方法。而 target(com.baobaotao.Seller)不匹配经过引介切面产生的NaiveWaiter代理对象。
相关文章
相关标签/搜索