主要實現思想:
通過實現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;}}
結果如下