一、背景
在实际的工作中,在服务与服务之间的交互中,异常是一个很重要的点,这里的异常有的是正常的业务异常,而有些确实程序本身抛出的异常,例如:服务A依赖服务B,服务B出现了NullPointerException,作为调用方,一定要做好异常的处理。下面是小弟在工作过程中,总结出来的一个统一处理异常的工具。
二、代码实现
1、定义服务返回结果DemoResult
public class DemoResult<T> implements Serializable { private String errorCode; private String message; private T t; private boolean isSuccess = true; public void setDemoResult(boolean isSuccess, String errorCode, String message) { this.isSuccess = isSuccess; this.errorCode = errorCode; this.message = message; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getT() { return t; } public void setT(T t) { this.t = t; } public boolean isSuccess() { return isSuccess; } public void setSuccess(boolean success) { isSuccess = success; } public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); } }
2、定义自己的异常DemoException
public class DemoException extends RuntimeException { private String errorCode; private int code; public DemoException(String message) { super(message); } public DemoException(String message, String exceptionCode) { super(message); this.errorCode = exceptionCode; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public int getCode() { return this.code; } public void setCode(int code) { this.code = code; } }
3、定义日志上下文LogContext
public class LogContext { private String bizLog; private long userId; public long getUserId() { return userId; } public void setUserId(long userId) { this.userId = userId; } public String getBizLog() { return bizLog; } public void setBizLog(String bizLog) { this.bizLog = bizLog; } public static LogContext build(String bizLog) { LogContext logContext = new LogContext(); logContext.setBizLog(bizLog); return logContext; } }
4、定义日志上下文的Holder
public class LogContextHolder { private static final ThreadLocal<LogContext> holder = new ThreadLocal<>(); public static void set(LogContext context) { if (context != null) { holder.set(context); } } public static LogContext getContext() { return holder.get(); } public static void remove() { holder.remove(); } public static String bizLog() { LogContext context = getContext(); if (context == null) { return ""; } return context.getBizLog(); } public static long userId() { LogContext context = getContext(); if (context == null) { return 0L; } return context.getUserId(); } }
5、定义异常处理的executor
public class DemoExecutor { private static final Logger logger = LoggerFactory.getLogger(DemoExecutor.class); public static <T extends DemoResult> T execut(Supplier<T> fn, Class<T> c, String bizCall, Object... param) { T result = null; String uuid = UUID.randomUUID().toString(); String logBiz = bizCall + "-" + uuid; try { logger.info("bizCall={},param={}", bizCall, param); Stopwatch stopwatch = Stopwatch.createStarted(); LogContextHolder.set(LogContext.build(uuid)); result = c.newInstance(); result = fn.get(); long costs = stopwatch.elapsed(TimeUnit.MILLISECONDS); result.setDemoResult(true, result.getErrorCode(), result.getMessage()); logger.info("BizCall={},result={}, costs={}ms", bizCall, result, costs); } catch (DemoException e) { if (e.getErrorCode() == null) { result.setDemoResult(false, e.getCode(), e.getMessage()); } if (e.getErrorCode() != null) { logger.error("error occurred at [" + logBiz + "] result=[" + result + "]", e); result.setDemoResult(false, e.getCode(), e.getMessage()); } else { logger.error("error occurred at [" + logBiz + "] result=[" + result + "]", e); } } catch (Throwable e) { if (result != null) { logger.error("error occurred at [" + logBiz + "] result=[" + result + "]", e); result.setDemoResult(false, e.getCode(), e.getMessage()); } else { logger.error("error occurred at [" + logBiz + "], error={}", e); } } finally { LogContextHolder.remove(); } return result; } }
6、说明:
此处只是一个简单的demo,具体的业务异常的定义,还要根据系统的业务要求。此外,使用的JDK版本最好是1.8以上,如果你的工作环境还没有用到JDK1.8,自己可以对该工具进行修改,满足自己的需求就行。