主要实现思想:
通过实现Convert接口来抽取公共组件,获取想要的标准模型。
现在有两个订单场景,一个保存订单,一个为更新订单。构造如下的服务类:
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@RecordOperate(desc = "保存订单", convertLog = SaveOrderConvert.class)
public Boolean saveOrder(SaveOrder saveOrder){
System.out.println("save order, orderId:"+ saveOrder.getId());
return true;
}
@RecordOperate(desc = "更新订单", convertLog = UpdateOrderConvert.class)
public Boolean updateOrder(UpdateOrder updateOrder){
System.out.println("update order, orderId:"+updateOrder.getOrderId());
return true;
}
}
对应的bean中订单属性名称会有差异,如何优雅的解决,后面会用一个转换接口,来获取对应的日志类。
定义的注释属性如下:
(这里有个注意点:
@Retention(RetentionPolicy.RUNTIME)注解用于表示注解的保留策略,在运行时保留注解,意味着注解不仅会被编译到字节码文件中。
@Target({ElementType.METHOD, ElementType.TYPE})
表示该注解可以应用于方法和类(包括接口、枚举)上。
)
@Target({ElementType.METHOD,ElementType.TYPE})
@Component
@Retention(RetentionPolicy.RUNTIME)
public @interface RecordOperate {
String desc() default "";
Class<? extends Convert> convertLog();
}
我们要将SaveOrder和UpdateOrder转换成对应的日志模型,用于日志输出:
public interface Convert<T> {
OperateLogDO convert(T t);
}
@Data
public class OperateLogDO {
private Long orderId;
private String result;
private String desc;
}
最终针对不同的订单类实现对应的转换类:
public class SaveOrderConvert implements Convert<SaveOrder>{
@Override
public OperateLogDO convert(SaveOrder saveOrder) {
OperateLogDO operateLogDO = new OperateLogDO();
operateLogDO.setOrderId(saveOrder.getId());
return operateLogDO;
}
}
最终!实现AOP的横向切面逻辑,要注意这边日志打印的过程应为异步,通过注解获取日志转换实例:
@Service
@Aspect
public class OperateLogAspect {
/**
* 定义切入点
*/
@Pointcut("@annotation(com.openapi.weekcode.aop.RecordOperate)")
public void pointcut(){}
private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,1,1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)
);
/**
* 定义横向逻辑
*/
@Around("pointcut()")
private Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = proceedingJoinPoint.proceed();
threadPoolExecutor.execute(() ->{
try {
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
RecordOperate annotation = methodSignature.getMethod().getAnnotation(RecordOperate.class);
Class<? extends Convert> convert = annotation.convertLog();
Convert logConvert = convert.newInstance();
OperateLogDO operateLogDO = logConvert.convert(proceedingJoinPoint.getArgs()[0]);
operateLogDO.setDesc(annotation.desc());
operateLogDO.setResult(result.toString());
System.out.println("insert operateLog:"+ operateLogDO.toString());
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
return result;
}
}
结果如下