Spring 的 AOP 使用

    最近在做 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”/>

  1. @Aspect放在类头上,把这个类作为一个切面。
  2. @Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。
  3. 5种通知
  • @Before,前置通知,放在方法头上。
  • @After,后置【finally】通知,放在方法头上。
  • @AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
  • @AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
  • @Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。

猜你喜欢

转载自my.oschina.net/freedemon/blog/1806076