• SpringBoot AOP异常日志处理 使用AOP+注解的方式进行异常日志的处理


    SpringBoot AOP异常日志处理 使用AOP+注解的方式进行异常日志的处理

    最近公司的一个项目需要将异常日志通过企业微信进行告警,由于消息推送已经有异常处理平台进行处理,现在只需要捕获异常信息,将信息发送到异常处理平台就可以了。可以选择的方案其实有两种,一个是springboot其实有全局异常处理,捕获到异常后可以进行消息推送。另一个就是通过AOP进行处理。因为全局异常处理不够灵活,比如不同的方法可能需要处理的异常类型不同,对不同的方法可能会有特殊的处理等等,最终选择了使用AOP+注解的方式进行异常日志的处理。

    异常日志注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface ExceptionLogService {
        /**
         * 系统模块名
         * @return
         */
        String moduleName() default "";
        /**
         * 业务名称
         * @return
         */
        String businessName() default "";
        /**
         * 日志前缀
         * @return
         */
        String messagePrefix() default "";
        /**
         * 需要推送消息的异常类型
         * @return
         */
        Class<? extends Throwable>[] exception() default {};
    }
    

    参数moduleNamebusinessName主要是为了定位异常位置,可写可不写,messagePrefix可以理解为对异常的说明,同时可以指定需要进行异常日志推送的异常类型,如果不指定则所有的异常都会进行推送。

    切面类

    @Aspect
    @Component
    public class ExceptionLogServiceAspect implements Ordered {
        private final static Logger logger= LoggerFactory.getLogger(ExceptionLogServiceAspect.class);
        @Autowired
        MessageService messageService;
        @Pointcut("@annotation(com.test.ExceptionLogService)")
        public void exceptionLogService(){
        }
        @Around("exceptionLogService()")
        public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            Object result=null;
            Throwable exception=null;
            MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
            ExceptionLogService annotation = signature.getMethod().getAnnotation(ExceptionLogService.class);
            String className = proceedingJoinPoint.getTarget().getClass().getSimpleName();
            String methodName = signature.getName();
            try {
                result = proceedingJoinPoint.proceed();
            } catch (Throwable throwable) {
                //获取需要推送消息的异常类型
                exception = getLogException(annotation, throwable);
                //构建消息内容
                String logContent = buildLogContent(annotation,className,methodName, exception);
                //推送消息到异常处理平台
                messageService.sendErrorMessage(logContent);
                //消息推送完成后将异常抛出,因为对于异常有另外的AOP进行处理,所以只是处理异常日志,然后直接抛出
                exception=throwable;
            }finally {
                if (exception!=null){
                    throw exception;
                }
            }
            return result;
        }
        /**
         * 根据ExceptionLogService 注解中的异常类型数组获取需要推送消息的异常类型,如果数组为空则所有的异常都进行消息推送
         * @param annotation
         * @param throwable
         * @return
         */
        private Throwable getLogException( ExceptionLogService annotation,Throwable throwable){
            Class<?>[] exceptions = annotation.exception();
            Throwable exception=null;
            if (exceptions==null || exceptions.length==0){
                exception=throwable;
            }else {
                for (Class<?> clazz : exceptions) {
                    if (clazz.isInstance(throwable)){
                        exception=throwable;
                        break;
                    }
                }
            }
            return exception;
        }
        /**
         * 构建异常消息内容
         * @param annotation ExceptionLogService注解
         * @param className 发生异常的类名称
         * @param methodName 发生异常的方法名称
         * @param throwable 抛出异常
         * @return 消息内容
         */
        private String buildLogContent(ExceptionLogService annotation, String className, String  methodName, Throwable throwable){
            if (annotation==null||throwable==null){
                return null;
            }
            String moduleName = annotation.moduleName();
            String businessName = annotation.businessName();
            String messagePrefix = annotation.messagePrefix();
            StringBuilder stringBuilder = new StringBuilder();
            if (StringUtils.isNotBlank(moduleName)){
                stringBuilder.append(moduleName).append(" 模块,");
            }
            if (StringUtils.isNotBlank(businessName)){
                stringBuilder.append(businessName).append(" 业务");
            }
            //如果异常消息为空,展示异常类型
            String message = throwable.getMessage();
            boolean isNull=false;
            if (StringUtils.isBlank(message)){
                message = throwable.getClass().getSimpleName();
                isNull=true;
            }
            stringBuilder.append("发生异常:").append(StringUtils.isBlank(messagePrefix) ? "" : messagePrefix);
            stringBuilder.append(isNull ? " 异常类型为:" : " 异常消息为:")
                    .append(message).append("。异常位置:").append(className)
                    .append(".class >>> ").append(methodName).append("()");
            String logContent = stringBuilder.toString();
            logger.error("AOP异常日志:{}",logContent);
            return logContent;
        }
        @Override
        public int getOrder() {
            return 1;
        }
    }
    

    异常消息格式

    moduleName 模块,businessName 业务发生异常,异常消息为:异常消息。异常位置:类名.class>>>方法名()
    

    对于异常消息为空的异常将展示异常的类型。

    测试

        @ExceptionLogService(moduleName = "测试模块",businessName = "test",exception = {NullPointerException.class})
        @Override
        public String logServiceTest() throws Exception {
            logger.info("testLog");
            throw new NullPointerException();
            return "test";
        }
    
    https://www.cnblogs.com/li956a/p/15108697.html
  • 相关阅读:
    利用jQuery Ajax技术实现每隔5秒向某页面传值
    POJ 题目2761 Feed the dogs(主席树||划分树)
    【翻译自mos文章】将expdp的dmp文件从asm磁盘组里边放到本地文件系统里边
    【算法拾遗】最大数和最小数
    WinMain和MFC的差别
    3.1 The Interpolating Polynomial(站点)
    在VS中设置比较和谐的字体和颜色的方法
    获取微信服务器IP地址
    关于bcg库记忆界面的问题及其解决办法
    Objective-C基础笔记(8)Foundation常用类NSString
  • 原文地址:https://www.cnblogs.com/sunny3158/p/16831111.html
Copyright © 2020-2023  润新知