@Aspect 切面AOP

Spring AOP 中@Pointcut的用法

格式:

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))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
  • 异常类型匹配(throws-pattern?)
  • 其中后面跟着“?”的是可选项

现在来看看几个例子:

1)execution(* *(..))  
//表示匹配所有方法  
2)execution(public * com. savage.service.UserService.*(..))  
//表示匹配com.savage.server.UserService中所有的公有方法  
3)execution(* com.savage.server..*.*(..))  
//表示匹配com.savage.server包及其子包下的所有方法 

在Spring 2.0中,Pointcut的定义包括两个部分:Pointcut表示式(expression)和Pointcut签名(signature)

//Pointcut表示式
@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
//Point签名
private void log(){} 
然后要使用所定义的Pointcut时,可以指定Pointcut签名
如下:
@Before("log()")

这种使用方式等同于以下方式,直接定义execution表达式使用

@Before("execution(* com.savage.aop.MessageSender.*(..))")

Pointcut定义时,还可以使用&&、||、! 这三个运算

@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
private void logSender(){}

@Pointcut("execution(* com.savage.aop.MessageReceiver.*(..))")
private void logReceiver(){}

@Pointcut("logSender() || logReceiver()")
private void logMessage(){}

这个例子中,logMessage()将匹配任何MessageSender和MessageReceiver中的任何方法。

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是针对方法的注解,为自定义注解
如:

/** * 选取切入点为自定义注解 */

@Pointcut("@annotation(com.honeywen.credit.annotation.PermissionCheck)")
 

要想把一个类变成切面类,需要两步: 


① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
② 在类上使用 @Aspect 注解 使之成为切面类

用@Aspect注解方式来实现前置通知、返回通知、后置通知、异常通知、环绕通知。

package com.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author wanjiadong
 * @description
 * @date Create in 15:09 2019/1/3
 */
@Aspect
@Component
public class AspectTest {

    @Pointcut("execution(* com.service..*.*(..))")
    public void pointcut(){

    }

    @Pointcut("@annotation(Override) || @within(Override)")
    public void pointcutAnnotation(){}

    /**
     * 前置通知:目标方法执行之前执行以下方法体的内容
     *
     * @param joinPoint
     */
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println(joinPoint.getArgs()[0].getClass());
        System.out.println(joinPoint.getArgs()[0].getClass().getGenericSuperclass());
        System.out.println(joinPoint.getArgs()[0].getClass().getSuperclass());
        System.out.println(joinPoint.getArgs()[0].getClass().getSuperclass().getSuperclass());
        System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(joinPoint.getArgs()));
    }

    /**
     * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        String methodName = proceedingJoinPoint.getSignature().getName();
        Object result = null;
        //目标参数
        Object args = proceedingJoinPoint.getArgs();
        //获取方法
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        //获取方法上的注解
        Override override = method.getAnnotation(Override.class);
        try {
            System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(proceedingJoinPoint.getArgs()));
            //执行目标方法
            result = proceedingJoinPoint.proceed();
            System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
        } catch (Throwable e) {
            System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);
        }
        System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");
        return result;
    }

    /**
     * 返回通知:目标方法正常执行完毕时执行以下代码
     *
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        result = "hahah";
        String methodName = joinPoint.getSignature().getName();
        System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】");
    }

    /**
     * 异常通知:目标方法发生异常的时候执行以下代码
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void throwing(JoinPoint joinPoint, Exception e) {
        e = new NullPointerException();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e);
    }

    /**
     * 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
     *
     * @param joinPoint
     */
    @After("pointcut()")
    public void after(JoinPoint joinPoint) {
        System.out.println("【后置通知】this is a afterMethod advice...");
    }
}

猜你喜欢

转载自blog.csdn.net/baidu_20608025/article/details/85700001