【SpringBoot应用篇】SpringBoot使用Aspect AOP注解实现日志管理(增强版)
- pom
- Log
- 实体类
- OperateLog
- Order
- Good
- LogAspect
- 转换器
- Convert
- GoodConvert
- OrderConvert
- AopController
- 启动类
- @EnableAutoOperateLog
需求: 需要保存的日志内容在方法的参数中,并且方法参数的类型对象不一样,且对象的属性名称不一样。
解决思路:
1、添加类型转换器Convert接口,需要转换的类型继承Convert接口
2、@Log
注解中添加Convert接口类型的Class属性
3、在切面环绕通知中进行处理
pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
Log
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
String desc() default "";
Class<? extends Convert> convert();
}
实体类
OperateLog
@Data
public class OperateLog {
private String id;
private String desc;
private String result;
}
Order
@Data
public class Order {
private String orderId;
}
Good
@Data
public class Good {
private String goodId;
}
LogAspect
@Component
@Aspect
public class LogAspect {
static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
static final ExecutorService executorService = new ThreadPoolExecutor(
1,
1,
10 ,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
@Pointcut("@annotation(cn.zysheep.anno.Log)")
public void pointcut(){};
@Around("pointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = proceedingJoinPoint.proceed();
executorService.execute(()->{
try {
MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
Log log = method.getAnnotation(Log.class);
if (log != null) {
Class<? extends Convert> convert = log.convert();
Convert instance = convert.newInstance();
OperateLog operateLog = instance.convert(proceedingJoinPoint.getArgs()[0]);
operateLog.setDesc(log.desc());
operateLog.setResult(result.toString());
logger.info("save operateLog: {}", operateLog);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
return result;
}
}
转换器
Convert
public interface Convert<T> {
OperateLog convert(T t);
}
GoodConvert
public class GoodConvert implements Convert<Good> {
@Override
public OperateLog convert(Good updateOrder) {
OperateLog operateLog = new OperateLog();
operateLog.setId(updateOrder.getGoodId());
return operateLog;
}
}
OrderConvert
public class OrderConvert implements Convert<Order> {
@Override
public OperateLog convert(Order saveOrder) {
OperateLog operateLog = new OperateLog();
operateLog.setId(saveOrder.getOrderId());
return operateLog;
}
}
AopController
@RestController
public class AopController {
@GetMapping("/saveOrder")
@Log(desc = "保存订单", convert = OrderConvert.class)
public String saveOrder(Order order) {
System.out.println(order);
return "ok";
}
@GetMapping("/saveGood")
@Log(desc = "保存商品", convert = GoodConvert.class)
public String saveGood(Good good) {
System.out.println(good);
return "ok";
}
}
启动类
@SpringBootApplication
public class AopApplication {
public static void main(String[] args) {
SpringApplication.run(AopApplication.class, args);
}
}
1、页面访问: http://localhost:8080/saveOrder?orderId=2
2、页面访问: http://localhost:8080/saveGood?goodId=1231
不同类型不同属性名称的值保存到了操作日志对象的id中
@EnableAutoOperateLog
使用SpringBoot自动配置的原理,启用热拔插效果
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({LogAspect.class})
public @interface EnableAutoOperateLog {
}
1、LogAspect 切面类去除@Component
注解,保留@Aspect
,否则切面不生效
2、启动类添加@EnableAutoOperateLog