美文网首页
浅谈java切面

浅谈java切面

作者: 七秒的记忆_d4a7 | 来源:发表于2020-10-13 11:43 被阅读0次

一、切面定义

切面 = 切点+通知

  • 切点(pointcut): 定义执行切面的入口点 ,这里切入点指示符

  • 通知:interceptor实现切面逻辑

二、切入点指示符的含义及使用(execution、within、this、target等)

  • execution:用于匹配方法执行的连接点 execution(* com.test.method.des...(..))
  • execution() 表达式的主体
  • 第一个“*”符号 表示返回值的类型任意
  • com.test.method.des AOP所切的服务的包名,即,需要进行横切的业务类
  • 包名后面的“..” 表示当前包及子包
  • 第二个“” 表示类名,即所有类
  • .*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型
  • within:用于匹配指定类型内的方法执行,within比较严格,它是严格匹配被代理对象类型的,不会理会继承关系,例如A继承了接口B,则within("B")不会匹配到A,但是within("B+")可以匹配到A
  • within(cn.java..*) . cn.java包及子包下的任何方法执行
  • within(java..IPointcutService+) . java包或所有子包下IPointcutService类型及子类型的任何方法
  • within(@cn..Secure *) 持有cn..Secure注解的任何类型的任何方法
  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配 , 例如A继承了B接口,则使用target("B"),target("A")均可以匹配到A, 我们pointcut 所选取的Join point 的所有者,直白点说就是: 指明拦截的方法属于那个类。
  • this:用于匹配当前AOP代理对象类型的执行方法,注意是AOP代理对象的类型匹配, 我们pointcut 所选取的Join point 的调用的所有者,就是说:方法是在那个类中被调。

三、切面应用实例

/**
 * 定义日志注解
 */

package test.anotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Log {
    String desc() default "打印日志";
}


/**
 * 定义日志切面
 */


package test.aspect;


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 test.anotation.Log;

import java.lang.reflect.Method;

import java.util.Arrays;
import java.util.List;

@Aspect
@Component
public class LogAspect {

    /**
     * 标注该方法体为后置通知,当目标方法执行成功后执行该方法体
     */
    @AfterReturning("within(test..*) && @annotation(rl)")
    public void addLogSuccess(JoinPoint jp, Log rl){
        Object[] parames = jp.getArgs();//获取目标方法体参数
        for (int i = 0; i < parames.length; i++) {
            System.out.println(parames[i]);
        }
        System.out.println(jp.getSignature().getName());
        String className = jp.getTarget().getClass().toString();//获取目标类名
        System.out.println("className:" + className);
        className = className.substring(className.indexOf("test"));
        String signature = jp.getSignature().toString();//获取目标方法签名
        System.out.println("signature:" + signature);
        System.out.println(rl.desc());
    }

    @Pointcut("@annotation(test.anotation.Log)")
    public void serviceMethodPointcut() {
       //切点
    }

    /**
     * 前置通知方法, 匹配test包下所有类的方法
     * 方法的返回值 和 test包下所有的类和方法,以及方法的形参 都抽象了
     * @param point
     * @return
     * @throws Throwable
     */
    @Before("execution(* test..*(..))")
    public void beforeAdvice(JoinPoint point){
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("@Before 前置通知 : 方法名 【 " + methodName + " 】and args are " + args);

    }

    /**
     * 环绕通知, 注解切点匹配
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("serviceMethodPointcut()")
    public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
        //通知方法
        String className = pjp.getTarget().getClass().toString();//获取目标类名
        System.out.println("className:" + className);

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();

        System.out.println("methodName:" + methodName);

        return pjp.proceed();
    }
}

相关文章

网友评论

      本文标题:浅谈java切面

      本文链接:https://www.haomeiwen.com/subject/pwcvpktx.html