• springboot学习5:使用aop


    springboot学习5:使用aop

    一、添加依赖

    <!--aop-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    

    二、编写切面和切入点以及要执行的通知

    引用依赖后就可以直接使用,不需要做其他额外的配置

    在切面类上加上@Aspect注解类声明当前类是一个切面类,再加上@Component注解注册为bean对象

    三、多个aop指向了同一个方法时的执行顺序

    默认情况下是随机的,可以通过在切面类上加@Order注解来指定顺序,该注解支持传入一个int型的value,数值越小的切面先执行。

    注意,先执行的aop一定后结束,可以把aop和原来方法的执行过程理解成一个同心圆,原来方法就是中间的圆心,

    如下图所示

    程序从左向右开始执行,先执行aop1的前置通知,再执行aop2的前置通知,然后再执行原来的方法逻辑,然后依次是aop2的后置通知,aop1的后置通知。如果使用的是环绕通知,要先把1和2两个通知中

    。。。前
    point.proceed(point.getArgs());//执行原来方法
    。。。后
    

    之前的逻辑按先1后2的顺序执行完,才会去执行这一句。方法执行完成之后按照先2后1的顺序执行后边的逻辑。

    四、使用aop实现MDC日志埋点和异常处理

    通过aop拦截到controller方法,给设置mdc标识

    通过aop拦截到controller方法,对controller方法可能抛出的异常进行处理

    分析:mdc埋点的aop切面和异常处理的aop切面都会切入到同一controller方法上,所以需要对aop的执行顺序进行配置。按我们的需求,需要在异常处理的切面中触发对原方法的执行,否则如果在mdc埋点的切面中触发了对原方法的执行,该切面中就会收到controller层的异常,我们的目的是让异常处理切面收到异常进行处理。

    所以aop的执行顺序应该是先执行mdc埋点的aop,再执行异常处理的aop。

    当然最好的方案是把这两个aop切面合成一个,这里是为了演示aop的执行顺序才拆成了两个

    mdc埋点的切面

    
    
    @Aspect
    @Component
    @Order(1)
    public class MdcValSetAspect {
    
        private final static Logger LOGGER= LoggerFactory.getLogger(CheckInLogAspectConfig.class);
    
        @Pointcut("execution( public * com.lyy.controller.*.*(..))")
        public void mdcValuePointcut(){}
    
        @Around("mdcValuePointcut()")
        public Object mdcValueSet(ProceedingJoinPoint point){
            String mdcValue= UUID.randomUUID().toString();
            System.out.println("mdcValueSet is run");
            MDC.put("MDC_VALUE", mdcValue);
            try {
                return point.proceed(point.getArgs());
            } catch (Throwable throwable) {
                LOGGER.error("mdcValueSet error",throwable);
                return ResultVoUtil.error(new MyException(9998,"mdcValueSet error:"+throwable.toString()));
            }
        }
    }
    
    

    使用order注解指定该切面第一个执行

    异常处理的切面

    @Aspect
    @Component
    @Order(Integer.MAX_VALUE)
    public class ExceptionHandlerAspect {
    
        private final static Logger LOGGER= LoggerFactory.getLogger(ExceptionHandlerAspect.class);
    
        @Pointcut("execution(public * com.lyy.controller.*.*(..))")
        public void exceptionHandlerPointcut(){}
    
        @Around("exceptionHandlerPointcut()")
        public Object exceptionHandler(ProceedingJoinPoint point){
            String methodFullName=point.getSignature().getDeclaringTypeName()+"."+point.getSignature().getName();
            try {
                return point.proceed(point.getArgs());
            } catch (Throwable throwable) {
                LOGGER.error(methodFullName+" is error,e:",throwable);
                return ResultVoUtil.error(new MyException(9999,"未知异常,"+throwable.toString()));
            }
        }
    }
    
    

    使用Order注解指定该切面最后一个执行

  • 相关阅读:
    java设计模式----迭代器模式和组合模式
    Redis实现消息的发布/订阅
    java设计模式----模板方法模式
    java设计模式----适配器模式
    Filter注入对象
    java设计模式----命令模式
    css3中animation的应用
    bootstrap的学习注意点
    关于animate的一些属性
    ie的兼容方法,条件注释的方法
  • 原文地址:https://www.cnblogs.com/chengxuxiaoyuan/p/12540711.html
Copyright © 2020-2023  润新知