Spring AOP的两种实现方式(AspectJ注解配置和方法配置)
AspectJ是一个java实现的AOP框架,它能够对java代码进行AOP编译(一般在编译期进行),让java代码具有AspectJ的AOP功能(当然需要特殊的编译器),可以这样说AspectJ是目前实现AOP框架中最成熟,功能最丰富的语言,更幸运的是,AspectJ与java程序完全兼容,几乎是无缝关联,因此对于有java编程基础的工程师,上手和使用都非常容易。
Spring AOP 与ApectJ 的目的一致,都是为了统一处理横切业务,但与AspectJ不同的是,Spring AOP 并不尝试提供完整的AOP功能(即使它完全可以实现),Spring AOP 更注重的是与Spring IOC容器的结合,并结合该优势来解决横切业务的问题,因此在AOP的功能完善方面,相对来说AspectJ具有更大的优势,同时,Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),因此Spring很机智回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ(静态织入)最根本的区别。在AspectJ 1.5后,引入@Aspect形式的注解风格的开发,Spring也非常快地跟进了这种方式,因此Spring 2.0后便使用了与AspectJ一样的注解。请注意,Spring 只是使用了与 AspectJ 5 一样的注解,但仍然没有使用 AspectJ 的编译器,底层依是动态代理技术的实现,因此并不依赖于 AspectJ 的编译器。
下面是Spring AOP的AspectJ注解式实现:
自定义注解
package com.dust.exercises.aop; import java.lang.annotation.*; /** * Created by zhaohongyang on 2018/8/14. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Action { String customName(); }
定义一个被拦截的方法(注解式拦截)
package com.dust.exercises.aop; import org.springframework.stereotype.Service; /** * Created by zhaohongyang on 2018/8/14. */ @Service public class DemoAnnotationService { //自定义注解中的自定义方法 @Action(customName="注解拦截的add操作") public void add(){ } }
定义一个被拦截的方法(方法式拦截)
package com.dust.exercises.aop; import org.springframework.stereotype.Service; /** * Created by zhaohongyang on 2018/8/14. */ @Service public class DemoMethodService { public void add(){ } }
定义切面的类
package com.dust.exercises.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * Created by zhaohongyang on 2018/8/14. */ @Aspect @Component public class LogAspect { @Pointcut("@annotation(com.dust.exercises.aop.Action)") public void annotationPointCut() { } @After("annotationPointCut()") public void after(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Action action = method.getAnnotation(Action.class); System.out.println("注解式拦截," + action.customName()); } @Before("execution(* com.dust.exercises.aop.DemoMethodService.*(..))") public void before(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("方法规则式拦截," + method.getName()); } }
配置类,使用@EnableAspectJAutoProxy 注解开启Spring 对AspectJ 代理的支持。
package com.dust.exercises.aop; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * Created by zhaohongyang on 2018/8/14. */ @Configuration @ComponentScan("com.dust.exercises.aop") @EnableAspectJAutoProxy public class AopConfig { }
运行
package com.dust.exercises.aop; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * Created by zhaohongyang on 2018/8/14. */ public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AopConfig.class); DemoMethodService demoMethodService = annotationConfigApplicationContext.getBean(DemoMethodService.class); DemoAnnotationService demoAnnotationService = annotationConfigApplicationContext.getBean(DemoAnnotationService.class); demoMethodService.add(); demoAnnotationService.add(); annotationConfigApplicationContext.close(); } }
结果