最近一段时间做项目总是用到AOP,在此做个简单的Spring Aop 日志记录Demo
简单的回顾一下Aop,他的代理方式有两种:
第一种:.静态代理(也就是编译时进行代理,如AspectJ)。
第二种:动态代理(动态又分为两种代理方式1.JDK动态代理 2.CGLIB动态代理,至于区别就不多说了)。
想要实现多个方法用同一个切面增强,怎么区别方法的模块名字和描述呢?当然方式很多,我这里用自定义
注解来实现:
第一步编写自定义注解:
---------自定义注解参数解释:
- /**
- * 表示对标记有xxx注解的类,做代理 注解@Retention可以用来修饰注解,是注解的注解,称为元注解。
- * Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,
- * 这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配
- * RententionPolicy使用。RetentionPolicy有3个值:CLASS RUNTIME SOURCE
- * 用@Retention(RetentionPolicy
- * .CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
- * 用@Retention(RetentionPolicy.SOURCE
- * )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
- * 用@Retention(RetentionPolicy.RUNTIME
- * )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,
- * 所以他们可以用反射的方式读取。RetentionPolicy.RUNTIME
- * 可以让你从JVM中读取Annotation注解的信息,以便在分析程序的时候使用.
- *
- * 类和方法的annotation缺省情况下是不出现在javadoc中的,为了加入这个性质我们用@Documented
- * java用 @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类。
- * @interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字
- @Target({ElementType. METHOD})
- @Retention(RetentionPolicy.RUNTIME )
- @Documented
- public @interface MethodRecordLog {
- String moduleName(); //模块名称
- String logType(); //日志类别
- String desc() default "描述信息" ;// 模块描述
- }
第二步编写日志记录类(也就是增强类)
- @Aspect
- @Component
- public class LogAspect {
- @Autowired
- private LogService LogService;
- //此注解是后置增强,方法执行成功后会执行
- @AfterReturning("within(com.xxx.*.web..*) && @annotation(mrl)")
- public void insertLogSuccess(final ProceedingJoinPoint pjp, final MethodRecordLog mrl){
- String moduleName = mrl.moduleName() ;
- String methodName = jp.getSignature().getName(); //获取目标方法名
- XXLog xxLog = new XXLog();
- xxLog.setXX(XX);//这里设置属性就不多写了
- LogService.saveLog(xxLog);//调用方法持久DB
- }
- //该方法体为异常通知,当目标方法出现异常时,执行该方法体
- @AfterThrowing(pointcut= "within(com.xxx.*.web..*) && @annotation(mrl)", throwing="ex")
- public void insertLog(final ProceedingJoinPoint pjp, final MethodRecordLog mrl, CRUDException ex){
- String moduleName = mrl.moduleName() ;
- String methodName = jp.getSignature().getName(); //获取目标方法名
- XXLog xxLog = new XXLog();
- xxLog.setXX(XX);//这里设置属性就不多写了
- LogService.saveLog(xxLog);//调用方法持久DB
- }
- //ProceedingJoinPoint继承自JoinPoint,在 JoinPoint的基础上添加了反射、具体参照javadoc
注:@AfterReturning为注解方法体成功执行后,执行的方法。@AfterThrowing为注解方法体抛出CRUDException 异常时执行的方法。ProceedingJoinPoint pjp参数可以获得注解方法体的相关值,包括类名、方法名、参数等信息。MethodRecordLog mrl参数为自定义注解的类,可以获得自定义注解的值
第三步在spring 的配置文件里面启动注解:
- <!-- 启用@AspectJ支持 -->
- <aop:aspectj-autoproxy />
第四步是controller层面自定义注解的用法:
- @JpfLog(moduleName="用户",logType="",desc= "添加用户")
- @RequestMapping(value = "/saveByUser")
- public String saveByUser(User user) throws CRUDException {
- int result = userService.saveUser(user);
- return "";
- }