利用spring aop统一处理异常和打日志

spring aop的概念,很早就写博客介绍了,现在在工作中真正使用。

我们很容易写出的代码

我们很容易写出带有很多try catch 和 logger.warn(),logger.error()的代码,这样一个方法本来的业务逻辑只有5行,有了这些,代码就变成了10行或者更多行,如:

public ResultDTO<UserDTO> queryUserByCardId(String cardId) {
        ResultDTO<UserDTO> result = new ResultDTO<UserDTO>();
        StringBuilder log = new StringBuilder();
        log.append("queryUserByCardId:" + cardId);
        try {
            checkCardIdNotNull(cardId);
            StationUserDO userDO = userDAO.queryUserByCardId(cardId);
            UserDTO stationUserDTO = DataTypeConvertUtils.DOToDTO(userDO);
            result.setData(stationUserDTO);
            logger.warn(log.append(" result:").toString() + result);
        } catch (StationErrorCodeException e) {
            //logger.error(log.append("catch StationErrorCodeException!").toString(), e);
            result.setSuccess(false);
            result.setErrorCode(e.getErrorCode().getErrorCode());
            result.setErrorMessage(e.getErrorCode().getErrorMessage());
        } catch (Exception e) {
            logger.error(log.append("catch Exception!").toString(), e);
            result.setSuccess(false);
            result.setErrorCode(StationErrorCodeConstants.STA10001.getErrorCode());
            result.setErrorMessage(StationErrorCodeConstants.STA10001.getErrorMessage());
        }
        return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

实际上,我们的业务逻辑就几行而已,中间却夹杂着那么多的异常处理代码及日志信息代码。


如何改进代码

我们可以使用springaop,做一个切面,这个切面专门做记录日志和异常处理的工作,这样就能减少重复代码。 
代码如下:

@Override
public ResultDTO<StationUserDTO>queryUserByCardId(String cardId) {
        ResultDTO<StationUserDTO> result = new ResultDTO<StationUserDTO>();
        checkCardIdNotNull(cardId);
        StationUserDO userDO = stationUserDAO.queryStationUserByCardId(cardId);
        StationUserDTO stationUserDTO = DataTypeConvertUtils.DOToDTO(userDO);
        result.setData(stationUserDTO);
        return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

我们在切面中做异常处理和记录日志:

@Aspect
public class CardServiceAspect {
    private final Logger logger = LoggerFactory.getLogger("card");
    // 切入点表达式按需配置
    @Pointcut("execution(* *.*(..)))")
    private void myPointcut() {
    }

    @Before("execution(* *.*(..)))")
    public void before(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        logger.warn(className + "的" + methodName + "执行了");
        Object[] args = joinPoint.getArgs();
        StringBuilder log = new StringBuilder("入参为");
        for (Object arg : args) {
            log.append(arg + " ");
        }
        logger.warn(log.toString());
    }

    @AfterReturning(value = "execution(* *.*(..)))", returning = "returnVal")
    public void afterReturin(Object returnVal) {
        logger.warn("方法正常结束了,方法的返回值:" + returnVal);
    }

    @AfterThrowing(value = "StationCardServiceAspect.myPointcut()", throwing = "e")
    public void afterThrowing(Throwable e) {
        if (e instanceof StationErrorCodeException) {
            logger.error("通知中发现异常StationErrorCodeException", e);
        } else {
            logger.error("通知中发现未知异常", e);
        }
    }

    @Around(value = "StationCardServiceAspect.myPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        logger.warn("前置增强...");
        Object result = null;
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Exception e) {
            ResultDTO resultDTO = new ResultDTO();
            if (e instanceof StationErrorCodeException) {
                StationErrorCodeException errorCodeException = (StationErrorCodeException) e;
                resultDTO.setSuccess(false);
                resultDTO.setErrorCode(errorCodeException.getErrorCode().getErrorCode());
                resultDTO.setErrorMessage(errorCodeException.getErrorCode().getErrorMessage());
            } else {
                resultDTO.setSuccess(false);
                resultDTO.setErrorCode(StationErrorCodeConstants.STA10001.getErrorCode());
                resultDTO.setErrorMessage(StationErrorCodeConstants.STA10001.getErrorMessage());
            }
            return resultDTO;
        }
        return result;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

然后我们在spring配置文件中配置切面

<!-- 配置切面的类 -->
<bean id="serviceAspect" class="com.lirui.StationCardServiceAspect"/>
<!-- 配置成注解方式寻找要被代理的对象 -->
<aop:aspectj-autoproxy/>
  • 1
  • 2
  • 3
  • 4

这样,我们就可以统一处理异常和日志了。


不足点

利用这种方式,只能打入参和出参,还有抛出异常时打异常日志,不能打方法运行中的中间值,目前我只能想到,方法中间值的日志,就是用原来的方式打出,不知道大家有没有什么好的方法。


spring aop的其他使用

推荐使用aspectJ来完成面向切面编程。我们还可以利用aop完成其他功能如记录程序运行时间等。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringAOP 全称为 Spring Aspect-Oriented Programming,是 Spring 框架中的一个模块,用于实现面向切面编程。在 SpringAOP 中,我们可以通过定义切点和通知来实现对目标对象的增强。 在平台开发中,我们可以使用 SpringAOP 来解决平台统一异常处理的问题。具体实现步骤如下: 1. 定义异常处理切面 在 SpringAOP 中,我们可以使用 @Aspect 注解来定义切面。在切面类中,我们需要定义一个处理异常的方法,并使用 @AfterThrowing 注解来指定这个方法是用于处理异常的。例如: ```java @Aspect public class ExceptionHandlerAspect { @AfterThrowing(pointcut = "execution(* com.example.*.*(..))", throwing = "ex") public void handleException(Exception ex) { // 处理异常的逻辑 } } ``` 在上述代码中,我们定义了一个名为 ExceptionHandlerAspect 的切面类,并在其中定义了一个名为 handleException 的方法,该方法的参数为 Exception 类型,用于处理异常。我们使用 @AfterThrowing 注解来指定这个方法是用于处理异常的,pointcut 属性用于指定切入点,这里我们使用 execution 表达式来匹配 com.example 包及其子包下的所有方法。 2. 配置 SpringAOPSpring 配置文件中,我们需要配置 SpringAOP。具体来说,我们需要定义一个名为 exceptionHandlerAspect 的 bean,并在其中指定切面的实现类。例如: ```xml <bean id="exceptionHandlerAspect" class="com.example.ExceptionHandlerAspect"/> <aop:config> <aop:aspect ref="exceptionHandlerAspect"> <aop:after-throwing method="handleException" throwing="ex"/> </aop:aspect> </aop:config> ``` 在上述代码中,我们首先定义了一个名为 exceptionHandlerAspect 的 bean,该 bean 的 class 属性指定了切面的实现类。然后,在 aop:config 标签中,我们使用 aop:aspect 标签来定义切面,并在其中指定切面的实现类。在 aop:aspect 标签中,我们使用 aop:after-throwing 标签来指定切面所织入的方法,method 属性用于指定处理异常的方法名,throwing 属性用于指定方法抛出的异常类型。 3. 使用统一异常处理 在业务代码中,当发生异常时,SpringAOP 会自动调用我们定义的异常处理方法。在这个方法中,我们可以根据具体的业务需求来处理异常。例如: ```java @Service public class UserServiceImpl implements UserService { @Override public void addUser(User user) { // 业务逻辑 try { // 执行业务操作 } catch (Exception e) { throw new RuntimeException("添加用户失败!"); } } } ``` 在上述代码中,当执行 addUser 方法时,如果发生异常SpringAOP 会自动调用我们定义的异常处理方法 handleException,并将异常对象作为参数传入该方法中。在 handleException 方法中,我们可以根据具体的业务需求来处理异常,例如记录日志、发送邮件等。 通过使用 SpringAOP,我们可以实现平台统一异常处理,避免代码中出现大量的 try-catch 代码块,提高代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值