非侵入式AOP实践(一):AspectJ

AOP,面向切面编程,可以不修改原来的代码,增加一些通用的、业务无关的逻辑,例如日志记录性能统计等。但一般都是使用spring框架提供的AOP支持和AspectJ,需要先写好切面逻辑,再在业务方法上加上设计好的注解:

    /**
    * 1.定义注解
    */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NILogBefore {
    }
    @Aspect
    public class NILogAnnotationAspect {
        /**
        * 2.定义切点:在使用NILogBefore注解的地方
        */
        @Pointcut("@annotation(com.null01.nonintrusivelog.annotation.NILogBefore)")
        private void beforePointCut(){
        }
    
        /**
        * 3.定义切面:@Before说明要在使用注解前就执行这个方法
        */
        @Before("beforePointCut()")
        public void before(JoinPoint joinPoint){
            //进行日志记录
            LogAction.before(joinPoint);
        }
     }
    /**
     * 4.切面配置:启用AspectJ自动代理
     */
    @Configuration
    @EnableAspectJAutoProxy
    public class AspectJConfiguration {
        @Bean
        public NILogAnnotationAspect nILogAnnotationAspect(){
            return new NILogAnnotationAspect();
        }
    }
    /**
    * 5.在目标方法上使用注解
    */
    @RestController
    public class TestController{
        @NILogBefore
        @RequestMapping("/h")
        public String hhh(String i,Integer e) throws Exception{
            System.err.println("h");
            return "h";
        }
     }

但是一旦不需要这个功能,这些没用的注解就会造成代码污染。想象一下在一个不能装lombok插件的ide里发现了大量lombok注解是多么痛苦。所以最好莫过于规避这些侵入代码的注解。

一、AspectJ的切点表达式

AspectJ是一个很强大的面向切面框架,定义切点的时候,除了可以通过@Pointcut("@annotation(com.null01.nonintrusivelog.annotation.NILogBefore)")指定注解为切点,还可以通过指示器中的execution()匹配连接点的执行方法:

    /**
    * 1.直接定义切面
    */
    @Aspect
    public class NILogDesignatorAspect {
        @Before("execution(* com.null01.nonintrusivelog.TestController.hhh(..))")
        public void testBefore(JoinPoint joinPoint){
            LogAction.before(joinPoint);
        }
    }
    /**
     * 2.切面配置:启用AspectJ自动代理
     */
    @Configuration
    @EnableAspectJAutoProxy
    public class AspectJConfiguration {
       @Bean
        public NILogDesignatorAspect nILogDesignatorAspect() throws Exception {
            return new NILogDesignatorAspect();
        }
    }

execution()指示器中直接指定目标方法,那么目标方法上就不用再加自定义注解了。其中指示器中的是切点表达式:*表示返回任意类型,com.null01.nonintrusivelog.TestController.hhh是指定了包名类名的目标方法,..表示匹配任意参数。虽然切点表达式支持指定某个包某个类中的所有方法(*表示匹配任意字符),但不支持匹配多个切点,要是遇到切点比较分散的情况,就要定义多个切点方法,比较繁琐。而且注解的参数一定要是编译期常量,写死在指示器上。这意味着配置切点的人一定要懂得切点表达式,而且不能通过设置解析配置文件的方式储存切点。

小小设想实践,更详细的代码见:https://github.com/RoxyJNg/non-intrusive-log

你可能感兴趣的:(非侵入式AOP实践(一):AspectJ)