现在项目中利用切面技术很容易处理异常,以下是我的给出的一个实践项目中处理异常日志的案例。
1.首先区分@Pointcut注解中execution属性定义:
expression="execution(* com.controller.*.*(..))" 切入点为com.controller包下的类的任意方法
expression="execution(* com.controller..*.*(..))" 切入点为com.controller包下子包的类的任意方法
实例:
项目中一般要定位controller包下以及所有子包下所有的类抛出的异常:
@Pointcut("execution(* com.test.web.controller..*.*(..)))")
public void testController() {
}
/**
* dubbo 切面(within注解是为了解决duboo服务切面定位不到的的问题)
*/
@Pointcut("@within(org.apache.dubbo.config.annotation.Service)")
public void dubooTestService() {
}
@Around(value = "testController()")
public Object aroundController(ProceedingJoinPoint joinPoint){
String function = joinPoint.getSignature().getName();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
Object args[] = joinPoint.getArgs();
Object result;
//这里是为了获取分布式追踪链路中的traceId,所以需要序列化获取json(分布式项目需要)
String params = "";
if(ArrayUtils.isNotEmpty(args) && args[0] != null){
for (Object arg : args) {
try {
log.info("直接打印参数 {}", arg);
params = JSON.toJSONString(arg);
} catch (Exception e) {
log.error("反序列化方法 {} 的请求参数异常", function, e);
params = "参数不能序列化";
}
}
} else {
params = "无参数。";
}
try {
log.info("[{}] request: {}", function, params);
result = joinPoint.proceed(args);
} catch (Throwable e) {
log.error("[{}] 服务器内部错误异常: ", function, e);
result=BaseResponse.withFail(SupplierError.SERVER_ERROR.getCode(),SupplierError.SERVER_ERROR.getError());
} finally {
stopWatch.stop();
}
if (result == null) {
log.error("[{}] result 为空", function);
result = BaseResponse.withFail(SupplierError.UNKNOWN_ERROR.getCode(),SupplierError.UNKNOWN_ERROR.getError());
}
log.info("[{}], response: {}, cost: {},", function, JSON.toJSONString(result),
stopWatch.getTotalTimeMillis());
return result;
} catch (Throwable e) {
log.error("切面执行异常:", e);
return BaseResponse.withFail(SupplierError.UNKNOWN_ERROR.getCode(), SupplierError.UNKNOWN_ERROR.getError());
}
}
@Around(value = "dubooTestService()")
public Object aroundService(ProceedingJoinPoint joinPoint){
....
}