在项目开发过程中,日志的打印是必不可少的,平常大部分都是针对单文件打印日志:如下所示
首先在class里面引入日志,
private static final Logger logger = LoggerFactory.getLogger(A.class);
然后在方法里面,针对逻辑打印日志,如:
method A(){
logger.erroe("XXXXX");
}
method B(){
logger.erroe("XXXXX");
}
这样有一个繁琐的地方就是每个需要打印日志的地方,都需要调用一遍logger.erroe("XXXXX");方法。于是我们就想着能够在一个地方调用logger.erroe("XXXXX");即可, 下面展示通过spring aop来做统一日志的管理代码如下
写法一、
package com.fpi;
import com.fpi.prd.des.api.vo.mobile.JResult;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
@Aspect
@Configuration
@Component
public class MobileAspect {
private static final JResult ERRO_RESULT = new JResult(null, JResult.State.DEFAULT);
private static final Logger logger = LoggerFactory.getLogger(MobileAspect.class);
//定义v1包下所有的类中的所有方法都需要被执行excudeService方法
//@Pointcut("execution(* com.fpi.prd.des.api.v1.*.*(需要被执行excudeService方法..))")
//定义 WmsController或 AqmsController下的所有方法都
@Pointcut("execution(* com.fpi.prd.des.api.v1.WmsController.*(..)) || execution(* com.fpi.prd.des.api.v1.AqmsController.*(..))")
public void excudeService() {
}
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
JResult jResult;
long start = System.currentTimeMillis();
try {
Object result = pjp.proceed();
jResult = new JResult(result);
} catch (Exception e) {
String info = e.getMessage();
if (StringUtils.isNotBlank(info)) {
jResult = new JResult(null, JResult.State.DEFAULT);
jResult.setMessage(info);
} else {
jResult = ERRO_RESULT;
}
logger.error(e.getMessage());
}
if (logger.isInfoEnabled()) {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
String uri = request.getRemoteAddr();
int port = request.getRemotePort();
logger.info(uri + ":" + port + "请求" + pjp.getSignature().getDeclaringType().getSimpleName() + "."
+ pjp.getSignature().getName()
+ Arrays.toString(pjp.getArgs())
+ " [耗时:"
+ (System.currentTimeMillis() - start + "ms]") + request.getQueryString());
}
return jResult;
}
}
在以上的代码中我们只在异常抛出的时候,调用了logger.eeor方法,这样就避免重复调用该方法了
写法二
切面
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Aspect @Component public class LoggerAdvice { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Before(value = "@annotation(loggerManage)") public void addBeforeLogger(JoinPoint joinPoint, LoggerManage loggerManage) { LocalDateTime now = LocalDateTime.now(); logger.info(now.toString() + "执行[" + loggerManage.logDescription() + "]开始"); logger.info(joinPoint.getSignature().toString()); logger.info(parseParames(joinPoint.getArgs())); } @AfterReturning(" @annotation(loggerManage)") public void addAfterReturningLogger(JoinPoint joinPoint, LoggerManage loggerManage) { LocalDateTime now = LocalDateTime.now(); logger.info(now.toString() + "执行 [" + loggerManage.logDescription() + "] 结束"); } @AfterThrowing(pointcut = "@annotation(loggerManage)", throwing = "ex") public void addAfterThrowingLogger(JoinPoint joinPoint, LoggerManage loggerManage, Exception ex) { LocalDateTime now = LocalDateTime.now(); logger.error(now.toString() + "执行 [" + loggerManage.logDescription() + "] 异常", ex); } private String parseParames(Object[] parames) { if (null == parames || parames.length <= 0) { return ""; } StringBuffer param = new StringBuffer("传入参数 # 个:[ "); int i = 0, j = 0; for (Object obj : parames) { j++; if (obj != null) { i++; if (j != parames.length) { param.append(obj.toString()).append(" ,"); } else { param.append(obj.toString()); } } } return param.append(" ]").toString().replace("#", String.valueOf(i)); } }
自定义注解
import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LoggerManage { public String logDescription(); }
使用
@RequestMapping(value = "/test", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
@ResponseBody
@LoggerManage(logDescription = "测试测试")
public Map<String, Object> getTest() throws IOException {
Map<String, Object> resultMap = new HashMap<String, Object>();
return resultMap;
}
下面博客链接是pointcut配置需要执行的方法的配置解释:
https://blog.youkuaiyun.com/bird_tp/article/details/90240887