Skip to content

Instantly share code, notes, and snippets.

@eagleon
Created April 12, 2018 13:06
Show Gist options
  • Save eagleon/acc818391125fdb7cff951f1ff2b5cac to your computer and use it in GitHub Desktop.
Save eagleon/acc818391125fdb7cff951f1ff2b5cac to your computer and use it in GitHub Desktop.
package com.jd.sea.pc.id.item.aspect;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.jd.epx.alarm.Alarm;
import com.jd.sea.pc.id.item.comm.annotation.Watch;
import com.jd.sea.pc.id.item.domain.comm.RpcResult;
import com.jd.sea.pc.id.item.domain.constant.ItemConstant.Http;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* Controller 统一处理日志,报警 Created by weiqingjing on 2018/4/4.
*/
@Slf4j
@Aspect
@Service
public class ControllerAspect {
@Pointcut("execution(* com.jd.sea.pc.id.item.controller..*.*(..)) && @annotation(com.jd.sea.pc.id.item.comm.annotation.Watch)")
public void controllerAspect() {
}
;
@Around("controllerAspect()")
public Object controllerAround(ProceedingJoinPoint pjp) {
log.debug("-----------------------------controller日志开始-----------------------------");
long startTime = System.currentTimeMillis();
Object o;
try {
initTrace();
paramValid(pjp);
o = pjp.proceed();
} catch (Throwable e) {
o = exceptionHandle(pjp, e);
}
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
log.info("{},耗时:{}毫秒", pjp.getSignature().toShortString(), (System.currentTimeMillis() - startTime));
log.debug("-----------------------------controller日志结束-----------------------------");
return o;
}
/**
* 方法调用之前
*/
@Before("controllerAspect()")
private void beforeMethod(JoinPoint point) {
String parameters = "";
String shortMethodName = "";
try {
shortMethodName = point.getSignature().toShortString();
parameters = Arrays.toString(point.getArgs());
log.info("{},params:{}", shortMethodName, parameters);
} catch (Throwable e) {
log.error("ControllerAspect.before执行异常,{},params:{}", shortMethodName, parameters, e);
Alarm.send("ControllerAspect.before执行异常:" + e.getMessage());
}
}
/**
* 方法调用后
*/
@AfterReturning(returning = "o", pointcut = "controllerAspect()")
private void afterMethod(JoinPoint point, Object o) {
String result = "";
String shortMethodName = "";
try {
shortMethodName = point.getSignature().toShortString();
result = JSON.toJSONString(o);
log.info("{},result:{}", shortMethodName, result);
returnTrace();
} catch (Exception e) {
log.error("ControllerAspect.after执行异常,{},result:{}", shortMethodName, result, e);
Alarm.send("ControllerAspect.after执行异常:" + e.getMessage());
}
}
/**
* 初始化trace
*/
private void initTrace() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// 判断Http header中是否有traceId字段,如果没有,则通过随机数生成
String traceId = null;
if (Strings.isNullOrEmpty(request.getHeader(Http.TRACE_HEADER))) {
traceId = request.getHeader(Http.TRACE_HEADER);
}
if (Strings.isNullOrEmpty(traceId)) {
traceId = UUID.randomUUID().toString();
}
MDC.put(Http.TRACE_HEADER, traceId);
}
/**
* resp 中包含trace
*/
private void returnTrace() {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
response.setHeader(Http.TRACE_HEADER, MDC.get(Http.TRACE_HEADER));
MDC.clear();
}
/*
* 发送自定义报警&记录日志
*/
private Object exceptionHandle(ProceedingJoinPoint point, Throwable ex) {
try {
String shortMethodName = point.getSignature().toShortString();
log.error("{} throw Exception", shortMethodName, ex);
String methodName = point.getSignature().getName();
Class<?> targetClass = point.getTarget().getClass();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
Method method = targetClass.getMethod(methodName, parameterTypes);
Watch watch = AnnotationUtils.getAnnotation(method, Watch.class);
if (watch.alarm()) {
log.error("alarm message:{}|{}|{}", watch.message(), shortMethodName, ex.getMessage());
Alarm.send("Controller|" + watch.message() + "|" + shortMethodName + "|" + ex.getMessage());
}
} catch (Exception e) {
log.error("ControllerAspect.exceptionHandle 方法执行异常", e);
return RpcResult.error("ControllerAspect.aspect 方法执行异常!");
}
return RpcResult.error(ex.getMessage() == null ? "服务器处理异常!" : ex.getMessage());
}
private void paramValid(JoinPoint point) throws RuntimeException {
// 获得切入目标对象
Object target = point.getThis();
// 获得切入方法参数
Object[] args = point.getArgs();
// 获得切入的方法
Method method = ((MethodSignature) point.getSignature()).getMethod();
// 执行校验,获得校验结果
Set<ConstraintViolation<Object>> validResult = validMethodParams(target, method, args);
if (!validResult.isEmpty()) {
StringBuilder message = new StringBuilder();
validResult.forEach(constraintViolation -> {
message.append(constraintViolation.getMessage()).append(",");
});
throw new RuntimeException(message.toString().substring(0, message.length() - 1));
}
}
private <T> Set<ConstraintViolation<T>> validMethodParams(T obj, Method method, Object[] params) {
return validator.validateParameters(obj, method, params);
}
private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
private final ExecutableValidator validator = factory.getValidator().forExecutables();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment