AspectJ 基础用法

引贴:java

  Aspectj与Spring AOP比较
  AspectJ语法详解 
 Spring中的AOP(五)——在Advice方法中获取目标方法的参数spring

配置方法

  1. < aop:aspect>:定义切面(切面包括通知和切点), 只须要定义通常的bean就行。
    //定义切面
    public class SleepHelperAspect{
        public void beforeSleep(){
            System.out.println("睡觉前要脱衣服!");
        }
    
        public void afterSleep(){
            System.out.println("起床后要穿衣服!");
        }
    }
    <bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect"></bean>
    
    <aop:aspectj-autoproxy/>
    <aop:config>
    <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
    <aop:aspect ref="sleepHelperAspect">
    <!--前置通知-->
    <aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/>
    <!--后置通知-->
    <aop:after method="afterSleep" pointcut-ref="sleepPointcut"/>
    </aop:aspect>
    </aop:config>
  2. < aop:advisor>:定义通知器(通知器跟切面同样,也包括通知(advice)和切点(PointCut)),通知必须实现Advice接口。
    //定义通知
    public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            System.out.println("睡觉前要脱衣服!");
        }
    
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
            System.out.println("起床后要穿衣服!");
        }
    }
    <bean id="sleepHelper" class="com.noob.aop.SleepHelper"></bean>
    
    <aop:aspectj-autoproxy/>
    <aop:config>
       <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
       <aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/>
    </aop:config>

基本概念

  1. Advice(通知、切面): 某个链接点所采用的处理逻辑,也就是向链接点注入的代码, AOP在特定的切入点上执行的加强处理。
    1. @Before: 标识一个前置加强方法,至关于BeforeAdvice的功能.
    2. @After: final加强,无论是抛出异常或者正常退出都会执行.
    3. @AfterReturning:  后置加强,似于AfterReturningAdvice, 方法正常退出时执行.
    4. @AfterThrowing:  异常抛出加强,至关于ThrowsAdvice.
    5. @Around: 环绕加强,至关于MethodInterceptor.
  2. JointPoint(链接点):程序运行中的某个阶段点,好比方法的调用、异常的抛出等。
  3. Pointcut(切入点):   JoinPoint的集合,是程序中须要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。
  4. Advisor(加强): PointCut和Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发
  5. @Aspect(切面):  一般是一个类的注解,类中能够定义切入点和通知
  6. AOP Proxy:AOP框架建立的对象,代理就是目标对象的增强。Spring中的AOP代理可使JDK动态代理,也能够是CGLIB代理,前者基于接口,后者基于子类。

Pointcut

表示式(expression)和签名(signature)express

//Pointcut表示式
@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
//Point签名
private void log(){}

由下列方式来定义或者经过 &&、 ||、 !、 的方式进行组合:框架

  • execution:用于匹配方法执行的链接点;ide

  • within:用于匹配指定类型内的方法执行;this

  • this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;        spa

  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;.net

  • args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;3d

  • @within:用于匹配因此持有指定注解类型内的方法;代理

  • @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;

  • @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;

  • @annotation:用于匹配当前执行方法持有指定注解的方法;

格式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

其中后面跟着“?”的是可选项

括号中各个pattern分别表示:

  • 修饰符匹配(modifier-pattern?)
  • 返回值匹配(ret-type-pattern):   能够为*表示任何返回值, 全路径的类名等
  • 类路径匹配(declaring-type-pattern?)
  • 方法名匹配(name-pattern):能够指定方法名 或者 *表明全部, set* 表明以set开头的全部方法
  • 参数匹配((param-pattern)):能够指定具体的参数类型。多个参数间用“,”隔开,各个参数也能够用"*" 来表示匹配任意类型的参数,".."表示零个或多个任意参数。
    eg. (String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数能够是任意类型,而第二个参数是String类型。
  • 异常类型匹配(throws-pattern?)

eg.

  • 任意公共方法的执行:execution(public * *(..))
  • 任何一个以“set”开始的方法的执行:execution(* set*(..))
  • AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
  • 定义在service包里的任意方法的执行: execution(* com.xyz.service.*.*(..))
  • 定义在service包和全部子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))
    第一个*表示匹配任意的方法返回值, ..(两个点)表示零个或多个,第一个..表示service包及其子包,第二个*表示全部类, 第三个*表示全部方法,第二个..表示方法的任意参数个数
  • 定义在pointcutexp包和全部子包里的JoinPointObjP2类的任意方法的执行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
  • pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)
  • pointcutexp包和全部子包里的任意类:within(com.test.spring.aop.pointcutexp..*)
  • 实现了Intf接口的全部类,若是Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)
    当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型
  • 带有@Transactional标注的全部类的任意方法: 
    • @within(org.springframework.transaction.annotation.Transactional)
    • @target(org.springframework.transaction.annotation.Transactional)
  • 带有@Transactional标注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)
    @within和@target针对类的注解,@annotation是针对方法的注解
  • 参数带有@Transactional标注的方法:@args(org.springframework.transaction.annotation.Transactional)
  • 参数为String类型(运行是决定)的方法: args(String)

JoinPoint

当使用@Around处理时,须要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。

经常使用的方法:

  • Object[] getArgs:返回目标方法的参数
  • Signature getSignature:返回目标方法的签名
  • Object getTarget:返回被织入加强处理的目标对象
  • Object getThis:返回AOP框架为目标对象生成的代理对象

织入

@AfterReturning(
            pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)",
            returning="returnValue")
    public void access(Date time, Object returnValue, String name) {
        System.out.println("目标方法中的参数String = " + name);
        System.out.println("目标方法中的参数Date = " + time);
        System.out.println("目标方法的返回结果returnValue = " + returnValue);
    }

表达式中增长了args(time, name)部分,意味着能够在加强处理的签名方法(access方法)中定义"time"和"name"两个同名属性。
这两个形参的类型由access方法同名参数类型指定,一旦指定了, 则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为String的方法(方法参数个数和类型如有不一样均不匹配);
access方法只须要知足"time", "name"参数的顺序和pointcut中args(time, name)的顺序相同便可,"returnValue"位置顺序无所谓。 

eg.

//将被access方法匹配
public String accessAdvice(Date d, String n) {
    System.out.println("方法:accessAdvice");
    return "aa";
}

切面执行顺序

一个方法只被一个Aspect类拦截

正常:

one-ok

异常:
one-exception

同一个方法被多个Aspect类拦截

优先级高的切面类里的加强处理的优先级老是比优先级低的切面类中的加强处理的优先级高。       
在“进入”链接点时,最高优先级的加强处理将先被织入(eg.给定的两个不一样切面类Before加强处理中,优先级高的那个会先执行);在“退出”链接点时,最高优先级的加强处理会最后被织入(eg.给定的两个不一样切面类After加强处理中,优先级高的那个会后执行)。

eg.

优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但因为Bean1的优先级高于Bean2的优先级,所以Bean1中的@Before先被织入。
Spring提供了以下两种解决方案指定不一样切面类里的加强处理的优先级:

  1. 让切面类实现org.springframework.core.Ordered接口:实现该接口的int getOrder()方法,该方法返回值越小,优先级越高
  2. 直接使用@Order注解来修饰一个切面类:使用这个注解时能够配置一个int类型的value属性,该属性值越小,优先级越高

同一个切面类里的两个相同类型的加强处理在同一个链接点被织入时,Spring AOP将以随机的顺序来织入这两个加强处理,没有办法指定它们的织入顺序。即便给这两个 advice 添加了 @Order 这个注解,也不行!

相关文章
相关标签/搜索