zoukankan      html  css  js  c++  java
  • SpringBoot中使用AOP

    SpringBoot中使用AOP

    AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

    对于我们开发中最常见的可能就是日志记录,事务处理,异常处理等等。。。

    原理

        AOP是通过动态代理实现的,动态代理又分为两个部分:JDK动态代理和CGLIB动态代理,AOP功能的使用还是比较简单的,把相关bean注入到Spring容器中,编写好相应的Aspect类即可,以下两点需要记住:

    1、AOP基于动态代理模式
    2、AOP是方法级别

    AOP术语

    • 切面(Aspect)
    一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现
    • 连接点(JoinPoint)

    在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在SpringAOP中,一个连接点总是表示一个方法的执行

    • 通知(Advice)

    在切面的某个特定的连接点上执行的动作。其中包括了AroundBeforeAfter等不同类型的通知。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链

    注解描述
    @Before 前置通知, 在方法执行之前执行
    @After 后置通知, 在方法执行之后执行
    @AfterReturn 返回通知, 在方法返回结果之后执行
    @AfterThrowing 异常通知, 在方法抛出异常之后
    @Around 环绕通知,围绕方法的执行
    • 切入点(PointCut)
    匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时),切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法

    常用切入点指示符

    1、execution表达式:用于匹配方法执行的连接点,属于方法级别

    语法:
    execution(修饰符 返回值类型 方法名(参数)异常)

    语法参数描述
    修饰符 可选,如public,protected,写在返回值前,任意修饰符填*号就可以
    返回值类型 必选,可以使用*来代表任意返回值
    方法名 必选,可以用*来代表任意方法
    参数 ()代表是没有参数,(..)代表是匹配任意数量,任意类型的参数,当然也可以指定类型的参数进行匹配,如要接受一个String类型的参数,则(java.lang.String), 任意数量的String类型参数:(java.lang.String..)等等。。。
    异常 可选,语法:throws 异常,异常是完整带包名,可以是多个,用逗号分隔

    符号

    符号描述
    * 匹配任意字符
    .. 匹配多个包或者多个参数
    + 表示类及其子类

    条件符

    符号描述
    &&、and
    ||
    !

    案例

    • 拦截com.dw.study包下的所有子包里的任意类的任意方法
      execution(* com.dw.study..*.*(..))
    • 拦截com.dw.study.Test2Controller下的任意方法
      execution(* com.dw.study.Test2Controller.*(..))
    • 拦截任何修饰符为public的方法
      execution(public * * (..))
    • 拦截com.dw.study下的所有子包里的以ok开头的方法
      execution(* com.dw.study..*.ok*(..))

    2、@annotation

    根据所应用的注解对方法进行过滤
    语法
    @annotation(注解全路径)
    实例
    对用了com.dw.annotations.Test注解的所有方法进行拦截
    @annotation(com.dw.annotations.Test)
    • 目标对象(Target Object)
    被一个或者多个切面所通知的对象。也被称做被通知对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理对象
     
     
     

    maven 依赖:

     <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-aop</artifactId>
             <version>2.2.2.RELEASE</version>
     </dependency>

    使用:

    @Aspect
    @Component
    public class MyCustomerAspect {
    
        /**
         * 定义切面,com.dengwei.springaopdemo.controller下面所有的方法进行拦截
         */
        @Pointcut("execution(public * com.dengwei.springaopdemo.controller.*.*(..))")
        public void myAspect(){}
    
        /**
         * 对于注解了 @MethodAspect的方法进行拦截
         */
        @Pointcut("@annotation(com.dengwei.springaopdemo.annotation.MethodAspect)")
        public void testMyAnnotationAspect() {}
    
    
        /**
         * 前置通知,在方法执行之前执行
         * @param joinPoint
         * @throws Throwable
         */
        @Before("myAspect()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            System.out.println(1 / 0);
            // 接收到请求,记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 记录下请求内容
            System.out.println("URL : " + request.getRequestURL().toString());
            System.out.println("HTTP_METHOD : " + request.getMethod());
            System.out.println("IP : " + request.getRemoteAddr());
            System.out.println("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs()));
        }
    
        /**
         * 前置通知,在方法执行之前执行
         * @param joinPoint
         */
        @Before("testMyAnnotationAspect()")
        public void doBeforeForAnnotation(JoinPoint joinPoint) {
            // 接收到请求,记录请求内容
            System.out.println("我是注解切面,被成功执行了");
        }
    
        /**
         * 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
         * @param joinPoint 连接点
         */
        @After("myAspect()")
        public void doAfter(JoinPoint joinPoint){
            System.out.println("方法最后执行.....");
        }
    
    
        /**
         * 后置通知,方法返回结果后执行
         *returning属性指定连接点方法返回的结果放置在returnResult变量中
         * @param returnResult 返回结果
         * @param joinPoint 连接点
         */
        @AfterReturning(returning = "returnResult", pointcut = "myAspect()")
        public void doAfterReturning(JoinPoint joinPoint, Object  returnResult){
            // 处理完请求,返回内容
            System.out.println("方法的返回值 : " + returnResult);
        }
    
        /**
         * 后置通知,当方法抛出异常时执行
         * @param joinPoint 连接点
         * @param runtimeException 当切点方法抛出runtimeException时执行
         */
        @AfterThrowing(value = "myAspect()", throwing = "runtimeException")
        public void doThrowsIng(JoinPoint joinPoint, RuntimeException runtimeException){
            System.out.println("方法异常时执行了我.....");
        }
    
    
        /**
         * 环绕通知,环绕增强,相当于MethodInterceptor
         * @param joinPoint
         * @return
         * @throws Throwable
         */
        @Around("myAspect()")
        public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("注解方式AOP拦截开始进入环绕通知.......");
            Object proceed = joinPoint.proceed();
            System.out.println("准备退出环绕......");
            return proceed;
        }
    
    
    }

    自定义注解:

    /**
     * @Author dw
     * @ClassName MethodAspect
     * @Description 注解在方法上
     * @Date 2020/7/10 14:39
     * @Version 1.0
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MethodAspect {
    
    }

    controller:

    @RestController
    public class TestAopController {
    
        @RequestMapping("/first")
        public Object first() {
            return "first controller";
        }
    
        @RequestMapping("/doError")
        public Object error() {
            return "如果报错了,是否会打印我";
        }
    
        @RequestMapping("/annotationAspectTest")
        @MethodAspect
        public Object annotationAspectTest(){
            return "测试注解切面";
        }
    
    }

     

  • 相关阅读:
    常见数据结构图文详解-C++版
    求单链表中环的起点,原理详解
    Qt Creator 整合 python 解释器教程
    Qt 共享库(动态链接库)和静态链接库的创建及调用
    qt creator 中的"提升为..."功能简介
    QT 操作 excel 教程
    网易2017校园招聘算法题c语言实现源码
    c语言版贪吃蛇小游戏
    mysql语法结构
    Spring MVC rest接收json中文格式数据显示乱码
  • 原文地址:https://www.cnblogs.com/dw3306/p/9615197.html
Copyright © 2011-2022 走看看