最近考虑需要记录客户对项目的操作日志。
如果在每一个客户都有可能操作的类增加日志对象,改动量太大,同时如果有新的功能增加,又要在新的功能上增加日志操作。
因此考虑后决定采用spring的aop功能。
spring的aop设置分为两种情况,一是通过xml配置,二是注解配置。
笔者使用的是springboot,直接省略掉了配置文件,因此采用的是注解配置的方式。
1、引入springboot包。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <!-- 日志 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!-- aop --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2、新建切面类。
新建一个类LogAspect,类上添加注解@Component,表示该类让spring自动扫描并装载。
再在类上添加注解@Aspect表示该类会作为一个切面,从而会被进行动态代理。
然后定义切点,切点可以用方法来表示,也可以用字符串来表示。
用方法表示:
定义方法pointCut2(){},方法上添加注解@PointCut(value),表示该方法是一个切点,注解里的值表示切点表达式,第一个*表示任意的返回类型,然后是完整类名,第二个*表示是domain下的所有类,第三个*表示所有方法,括号中的两点表示任意参数。这一个切点表达式的完整意思是在包com.yxf.demo.springboot.domain下的所有类的所有方法。
@Pointcut("execution(* com.yxf.demo.springboot.domain.*.*(..))") public void pointCut2(){}
用字符串定义:
只是将切点表达式创建为一个字符串。
String pointcut = "execution(* com.yxf.demo.springboot.domain.*.*(..))"
切点设置完成后,定义我们需要的通知类型。
spring aop分为五种通知类型:
- @Before 前置通知
- @After 后置通知(不论方法是否执行成功,即使抛出异常也会被通知)
- @AfterReturing 返回通知(方法执行成功才会被通知)
- @AfterThrowing 异常通知(方法执行抛出异常才会被通知)
- @Around 环绕通知(方法执行前被通知,执行后也会被通知,同时返回参数会由通知类进行返回。)
一个完整的demo类如下:
package com.yxf.demo.springboot.config; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class LogAspect { @Pointcut("execution(* com.yxf.demo.springboot.domain.*.*(..))") public void pointCut2(){} @Before("pointCut2()") public void before(JoinPoint join){ System.out.println("***************************before***************************"); Object[] obj = join.getArgs(); if(obj != null && obj.length > 0) { for (int i = 0; i < obj.length; i++) { System.out.println("before[" + i + "]:" + obj[i]); } } System.out.println("getKind:" + join.getKind()); System.out.println("getTarget:" + join.getTarget().getClass()); System.out.println("getThis:" + join.getThis().getClass()); System.out.println("getSignature:" + join.getSignature()); System.out.println("getSourceLocation:" + join.getSourceLocation().getClass()); System.out.println("getStaticPart:" + join.getStaticPart()); } @Around("pointCut2()") public Object Around2(ProceedingJoinPoint p) { Object[] o = p.getArgs(); if(o != null && o.length > 0) { for (int i = 0; i < o.length; i++) { String s = (String) o[i]; System.out.println("s[" + i + "]=" + s); } } // System.out.println("i="+dwbm); System.out.println("***************************around***************************"); Object obj = null; try { obj = p.proceed(); System.out.println("result=" + obj.toString()); } catch (Throwable e) { e.printStackTrace(); } return obj; } }
3、测试