AspectJ

作者: 郑凌峰 | 来源:发表于2018-06-22 10:46 被阅读0次

    一、AspectJ概念
    demo演示

    pointcut action():call(* aop.Demo.*(..));
    

    切点的语法:关键字为pointcut,切点名字以及匹配表达式,目标方法调用形式:call()或者execution()

    5种通知:

    /**
         * 执行前通知
         */
        before():action(){
            System.out.println("beforeAction");
        }
    
        /**
         * 执行后通知
         */
        after():action(){
            System.out.println("afterAction");
        }
    
        /**
         * 目标方法return之后通知,带回返回值
         */
        after() returning(String s):adviceReturn(){
            System.out.println("返回值为:"+s);
        }
    
        /**
         * 目标方法抛出异常后通知,带回异常类型
         */
        after() throwing(Exception e):error(){
            System.out.println("抛出异常:"+e.toString());
        }
    
        /**
         * 环绕通知,可通过proceed()控制目标方法在何时执行
         */
        Object around():aroundAction(){
            System.out.println("Around 目标方法前执行");
            Object result=proceed();//执行目标方法
            System.out.println("Around 目标方法后执行");
            return result;
        }
    
    aspectj简介.png

    二、Spring AOP
    demo演示
    容器管理统一都交给Spring,包括切面类,配置跟平常的Spring项目一样
    需要额外加入的配置项:<aop:aspectj-autoproxy/>

    切点定义:

    @Pointcut("execution(* aop.*.*(..))")
    private void allPackage(){}
    @Pointcut("within(aop.child..*)")
    private void allPackage(){}
    

    execution:基于方法匹配
    语法结构:execution([修饰符] 返回值类型 方法名(参数) ) []为可选项
    within:基于类名匹配
    语法结构:within(包、类名)

    匹配表达式规则:
    *:匹配任何数量字符;
    ..:在方法参数中匹配任何数量参数,在包路径描述时匹配所有方法,包括子路径的
    +:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

    bean:匹配特定名称的Bean对象的执行方法

    //匹配名称中以Service结尾的Bean。
    @Pointcut("bean(*Service)")
    private void pointcut(){}
    

    @within:匹配所有带指定注解的类的方法

    //匹配使用了注解的类
    @Pointcut("@within(com.annotation.DemoAnnotation)")
    private void pointcut(){}
    

    @annotation(com.annotation.DemoAnnotation) : 匹配所有带有该注解的方法

    //匹配使用了注解的方法
    @Pointcut("@annotation(com.annotation.DemoAnnotation)")
    private void pointcut(){}
    

    通知:

        @Before("execution(* aop..*(..))")
        public void beforeAction(JoinPoint joinPoint){
            System.out.println("AOPbeforeAction");
        }
    
        @After("allPackage()")
        public void afterAction_p(JoinPoint joinPoint){
            System.out.println("afterAction_p");
        }
    
        @AfterReturning(value = "execution(* aop.User.returnVal())",returning = "value")
        public void afterReturn(JoinPoint joinPoint,String value){
            System.out.println("afterReturn--"+value);
        }
    
        @AfterThrowing(value = "execution(* aop.User.*(..))",throwing = "e")
        public void afterThrowing(JoinPoint joinPoint,Throwable e){
            System.out.println("AfterThrowing--"+e);
        }
    
      /**
         * 环绕通知既可以在目标方法前执行也可在目标方法之后执行,并可以控制目标方法执行,
         * 第一个参数必须是ProceedingJoinPoint,通过该对象的proceed()方法来执行目标方法,
         * 并获取到返回值,同样的,ProceedingJoinPoint对象也是可以获取目标对象的信息,
         * 如类名称,方法参数,方法名称等等。
         */
        @Around("!execution(* aop.User.throwError(..))")
        public Object around(ProceedingJoinPoint joinPoint){
            System.out.println("Around前");
            try {
                Object result = joinPoint.proceed();
                System.out.println("Around后");
                return result;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                return null;
            }
        }
    

    切面:

    @Aspect
    @Component
    public class Aop {
    
        @Pointcut("within(aop.child..*)")
        private void allPackage(){}
    
        @Before("execution(* aop..*(..))")
        public void beforeAction(JoinPoint joinPoint){
            System.out.println("AOPbeforeAction");
        }
    
        @After("allPackage()")
        public void afterAction_p(JoinPoint joinPoint){
            System.out.println("afterAction_p");
        }
    }
    

    可以通过先定义切点再在通知中引入,或者直接在通知中定义

    JoinPoint 方法 返回值 描述 例如
    getArgs() Object[] 获取连接点的入参 [123,"abc"]
    getSignature() Signature 获取连接点方法的签名
    Signature 方法 返回值 描述 例如
    getDeclaringType() Class 获取声明该连接点方法的类的类型 com.Test
    getDeclaringTypeName() String 获取声明该连接点方法的类的名字 “com.Test”
    getName() Signature 获取方法名 createZan
    MethodSignature类api
    
    方法 返回值 描述 例如
    getReturnType() Class 获取方法的返回值类型 java.lang.Long
    getParameterTypes() Class[] 获取方法入参的类型 [java.lang.Long,java.lang.String]
    getParameterNames() String[] 获取方法入参的名字 [id,name]

    相关文章

      网友评论

          本文标题:AspectJ

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