最近在做 iot 的一个项目,将家里和小区的设备接入到云端的物联网项目。项目很大,已经服务化了,各个模块都抽成了独立的服务,服务之间通过HSF通讯。我主要负责 homeLink接口。拿到项目,发现项目中所有的异常都抛出去了,没有进行处理。难道别人调用的时候,需要catch异常?后来在调试一个接口的时候, 通过 debug 才发现:原来项目里使用aspect做切面,对异常进行统一处理.
code :
@Aspect
@Component
public class HsfAspect {
private static final Logger logger_hsf = LoggerFactory.getLogger(LogFileEnum.HSF_SERVICE.getName());
private static final Logger logger_error = LoggerFactory.getLogger(LogFileEnum.ERROR.getName());
@Pointcut("execution(public * com.netease.iotx.service.hsf.provider..*.*(..))")
public void hsfLog() {}
@Around("hsfLog()")
public Object logFun(ProceedingJoinPoint joinPoint) {
Long startTime = System.currentTimeMillis();
Object result = null;
Throwable exception = null;
try {
result = joinPoint.proceed();
return result;
} catch (IoTxException e) {
result = new IoTxResult<>(e.getCode(), e.getMessage());
return result;
} catch (Throwable throwable) {
//error日志打印出堆栈,方便排查问题.
logger_error.error("UNEXPECTED ERROR: [INTERFACE : {}], [METHOD : {}], [ARGS : {}], EXCEPTION : ",
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
joinPoint.getArgs(),
throwable);
exception = throwable;
return new IoTxResult<>(IoTxCodes.SERVER_ERROR);
} finally {
long timeSpend = System.currentTimeMillis() - startTime;
if (exception != null) {
logger_hsf.error("[INTERFACE : {}], [METHOD : {}], [ARGS : {}], [EXCEPTION : {}], [SPEND TIME : {}]",
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
joinPoint.getArgs(),
exception.getMessage(),
timeSpend);
}
if (result != null) {
String resultdata = null;
if (result instanceof IoTxResult) {
Object data = ((IoTxResult)result).getData();
resultdata = (data != null) ? data.toString() : "";
}
logger_hsf.info("[INTERFACE : {}], [METHOD : {}], [ARGS : {}], [RESULT : {}], [RESULT_DATA : {}], [SPEND TIME : {}]",
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
joinPoint.getArgs(),
result.toString(),
resultdata,
timeSpend);
}
}
}
}
查了一些资料, Spring使用的 AOP 注解分为三个层次:
前提条件是在xml中配置<aop:aspectj-autoproxy proxy-target-class=”true”/>
- @Aspect放在类头上,把这个类作为一个切面。
- @Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。
- 5种通知
- @Before,前置通知,放在方法头上。
- @After,后置【finally】通知,放在方法头上。
- @AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
- @AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
- @Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。