最近技術部忽然颳起一陣 review
代碼的小風,挨個項目組過代碼,按理說這應該是件挺好的事,讓別人指出本身代碼中的不足,查缺補漏,對提高自身編碼能力有很大幫助,畢竟本身審查很容易「陶醉
」在本身寫的代碼裏。 git
不過,代碼 review
的詳細程度使人髮指,一行一行的分析,簡直就是個培訓班啊。不誇張的說,若是我村裏僅有縣重點小學學歷的四大爺,來聽上一個月後,保證能上手開發,666~github
既然組內氣氛到這了,咱也得行動起來,要不哪天評審到個人代碼,讓人家指指點點的內心多少有點不舒服,與其被動優化代碼不如主動出擊~web
選優化代碼的方向,方法入參和返回結果日誌首當其衝,每一個方法都會有這兩個日誌,一大堆冗餘的代碼,並且什麼樣的打印格式都有,很是的雜亂。spring
public OrderDTO getOrder(OrderVO orderVO, String name) {
log.info("訂單詳情入參:orderVO={},name={}", JSON.toJSONString(orderVO), name);
OrderDTO orderInfo = orderService.getOrderInfo(orderVO);
log.info("訂單詳情結果:orderInfo={}", JSON.toJSONString(orderInfo));
return orderInfo;
}
複製代碼
下邊咱們利用 AOP
實現請求方法的入參、返回結果日誌統一打印,避免日誌打印格式雜亂,同時減小業務代碼量。springboot
自定義切面註解@PrintlnLog
用來輸出日誌,註解權限 @Target({ElementType.METHOD})
限制只在方法上使用,註解中只有一個參數 description
,用來自定義方法輸出日誌的描述。app
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface PrintlnLog {
/**
* 自定義日誌描述信息文案
*
* @return
*/
String description() default "";
}
複製代碼
接下來編寫@PrintlnLog
註解對應的切面實現,doBefore()
中輸出方法的自定義描述、入參、請求方式、請求url、被調用方法的位置等信息,doAround()
中打印方法返回結果。編輯器
注意:
如何想指定切面在哪一個環境執行,能夠用@Profile
註解,只打印某個環境的日誌。學習
@Slf4j
@Aspect
@Component
//@Profile({"dev"}) //只對某個環境打印日誌
public class LogAspect {
private static final String LINE_SEPARATOR = System.lineSeparator();
/**
* 以自定義 @PrintlnLog 註解做爲切面入口
*/
@Pointcut("@annotation(com.chengxy.unifiedlog.config.PrintlnLog)")
public void PrintlnLog() {
}
/**
* @param joinPoint
* @author fu
* @description 切面方法入參日誌打印
* @date 2020/7/15 10:30
*/
@Before("PrintlnLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String methodDetailDescription = this.getAspectMethodLogDescJP(joinPoint);
log.info("------------------------------- start --------------------------");
/**
* 打印自定義方法描述
*/
log.info("Method detail Description: {}", methodDetailDescription);
/**
* 打印請求入參
*/
log.info("Request Args: {}", JSON.toJSONString(joinPoint.getArgs()));
/**
* 打印請求方式
*/
log.info("Request method: {}", request.getMethod());
/**
* 打印請求 url
*/
log.info("Request URL: {}", request.getRequestURL().toString());
/**
* 打印調用方法全路徑以及執行方法
*/
log.info("Request Class and Method: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
}
/**
* @param proceedingJoinPoint
* @author xiaofu
* @description 切面方法返回結果日誌打印
* @date 2020/7/15 10:32
*/
@Around("PrintlnLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
String aspectMethodLogDescPJ = getAspectMethodLogDescPJ(proceedingJoinPoint);
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
/**
* 輸出結果
*/
log.info("{},Response result : {}", aspectMethodLogDescPJ, JSON.toJSONString(result));
/**
* 方法執行耗時
*/
log.info("Time Consuming: {} ms", System.currentTimeMillis() - startTime);
return result;
}
/**
* @author xiaofu
* @description 切面方法執行後執行
* @date 2020/7/15 10:31
*/
@After("PrintlnLog()")
public void doAfter(JoinPoint joinPoint) throws Throwable {
log.info("------------------------------- End --------------------------" + LINE_SEPARATOR);
}
/**
* @param joinPoint
* @author xiaofu
* @description @PrintlnLog 註解做用的切面方法詳細細信息
* @date 2020/7/15 10:34
*/
public String getAspectMethodLogDescJP(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
return getAspectMethodLogDesc(targetName, methodName, arguments);
}
/**
* @param proceedingJoinPoint
* @author xiaofu
* @description @PrintlnLog 註解做用的切面方法詳細細信息
* @date 2020/7/15 10:34
*/
public String getAspectMethodLogDescPJ(ProceedingJoinPoint proceedingJoinPoint) throws Exception {
String targetName = proceedingJoinPoint.getTarget().getClass().getName();
String methodName = proceedingJoinPoint.getSignature().getName();
Object[] arguments = proceedingJoinPoint.getArgs();
return getAspectMethodLogDesc(targetName, methodName, arguments);
}
/**
* @param targetName
* @param methodName
* @param arguments
* @author xiaofu
* @description 自定義註解參數
* @date 2020/7/15 11:51
*/
public String getAspectMethodLogDesc(String targetName, String methodName, Object[] arguments) throws Exception {
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
StringBuilder description = new StringBuilder("");
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description.append(method.getAnnotation(PrintlnLog.class).description());
break;
}
}
}
return description.toString();
}
}
複製代碼
咱們在須要打印入參和返回結果日誌的方法,加上@PrintlnLog
註解,並添加自定義方法描述。flex
@RestController
@RequestMapping
public class OrderController {
@Autowired
private OrderService orderService;
@PrintlnLog(description = "訂單詳情Controller")
@RequestMapping("/order")
public OrderDTO getOrder(OrderVO orderVO, String name) {
OrderDTO orderInfo = orderService.getOrderInfo(orderVO);
return orderInfo;
}
}
複製代碼
代碼裏去掉 log.info
日誌打印,加上 @PrintlnLog
看一下效果,清晰明瞭。 Demo GitHub
地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-aop-unifiedlog優化
原創不易,燃燒秀髮輸出內容,若是有一丟丟收穫,點個贊鼓勵一下吧!
整理了幾百本各種技術電子書,送給小夥伴們。關注公號回覆【666】自行領取。和一些小夥伴們建了一個技術交流羣,一塊兒探討技術、分享技術資料,旨在共同窗習進步,若是感興趣就加入咱們吧!