如何做出一个标准化记录流水日志(Demo)
昨天晚上 在b站刷到了 极海Channel 海哥的视频 也想去跟着实现一个,作为学习的demo,主要学习思路
可能存在的问题:
- 可能每一个需要收集的类里取参数的字段可能是不一样的如何去处理
- 如何可以让他更好的作用于新的业务代码上
项目代码日志
问题实现
以订单为例子 :
- SaveOrder
- UpdateOrder
两个对象的字段名字和类型都可能不同
代码语言:javascript复制SaveOrder
public class SaveOrder {
private Long id;
}
代码语言:javascript复制UpdateOrder
public class UpdateOrder {
private Long orderId;
}
定义日志流水数据对象
代码语言:javascript复制OperateLogDo
public class OperateLogDo {
private Long orderId;
private String desc;
private String result;
}
配置需要生成注释的类型转换接口
接口
这个接口主要是用来对应的不同的类需要生成不同的日志,我们需要拿到他的唯一id 对象就可以操作数据了
代码语言:javascript复制public interface Convert<PARAM> {
OperateLogDo convert(PARAM param);
}
代码语言:javascript复制实现类
public class SaveOrderConvert implements Convert<SaveOrder> {
@Override
public OperateLogDo convert(SaveOrder saveOrder) {
OperateLogDo operateLogDo = new OperateLogDo();
operateLogDo.setOrderId(saveOrder.getId());
return operateLogDo;
}
}
代码语言:javascript复制public class UpdateOrderConvert implements Convert<UpdateOrder> {
@Override
public OperateLogDo convert(UpdateOrder updateOrder) {
OperateLogDo operateLogDo = new OperateLogDo();
operateLogDo.setOrderId(updateOrder.getOrderId());
return operateLogDo;
}
}
定义注解
代码语言:javascript复制RecordOperate 1、 desc 是用来放日志类型的描述 2、 convert 用来放日志类型的转变类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RecordOperate {
//日志描述
String desc() default "";
Class<? extends Convert> convert();
}
定义切面
代码语言:javascript复制OperateAspect
@Component
@Aspect
public class OperateAspect {
//根据需求来定义需要多少线程 编写测试demo需求并不高
private ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1, TimeUnit.SECONDS,new LinkedBlockingDeque<>(100));
@Around("@annotation(com.hyc.annotation.RecordOperate)")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = proceedingJoinPoint.proceed();
executor.execute(()->{
try {
MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
RecordOperate recordOperate = signature.getMethod().getAnnotation(RecordOperate.class);
Class<? extends Convert> convert = recordOperate.convert();
Convert LogConvert = convert.newInstance();
OperateLogDo operateLogDo = LogConvert.convert(proceedingJoinPoint.getArgs()[0]);
operateLogDo.setDesc(recordOperate.desc());
operateLogDo.setResult(result.toString());
System.out.println("insert opreateLog" JSON.toJSONString(operateLogDo));
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
return result;
}
}
查看结果
启动测试
代码语言:javascript复制@SpringBootApplication
public class AopPublicLogApplication implements CommandLineRunner {
@Autowired
OrderService orderService;
public static void main(String[] args) {
SpringApplication.run(AopPublicLogApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
SaveOrder saveOrder = new SaveOrder();
saveOrder.setId(1L);
orderService.saveOrder(saveOrder);
UpdateOrder updateOrder = new UpdateOrder();
updateOrder.setOrderId(2L);
orderService.updateOrder(updateOrder);
}
}
可以看到 我们确实拿到了不同类不同字段的id 而且跟着海哥的思路 我们编写的这个demo符合开闭原则,
在不改动源代码的情况下拓展功能。很简单的一个小demo但是可以拓展我们平时开发中的思路 多多的思考尽可能的优雅的实现业务和一些需要公共抽取的方式