【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



















