主要实现思想:
通过实现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>{@Overridepublic 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;}}
结果如下