springboot整合AOP

3 篇文章 0 订阅
2 篇文章 0 订阅

1.AOP使用场景

  1. 日志记录
  2. 权限控制
  3. 缓存处理
  4. 监控
  5. 事务处理

2.pom依赖

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

3.自定义注解

如果需要更详细了解如何自定义注解见https://blog.csdn.net/qq_42513284/article/details/109047862

package com.qin.test.annotation;

import org.springframework.stereotype.Component;

import java.lang.annotation.*;

/**
 * @author 小枫
 * @version 1.0.0
 * @date 2020/10/12 21:30
 * @desciption MyTestAnnotation
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyTestAnnotation {

    String value() default "";
    String name() default "";
}

3.AOP切面

package com.qin.test.aspect;

import com.qin.test.annotation.MyTestAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author 小枫
 * @version 1.0.0
 * @date 2020/10/12 21:30
 * @desciption MyTestAspect
 */

@Component
@Aspect
public class MyTestAspect {

    /**
     * 定义切入点,切入点为com.qin..TestController.te*(..)
     * public: 方法权限修饰符,可以为*,*为任意
     * *: 方法返回值,可以为*    Object+: Object以及子类,但不包含void
     * ..: com.qin下的所有包
     * te*: 以te为前缀的方法
     * (..): 任意参数,可以为 (String,..)、(String,*)、(Object+,..)等
     * 通过@Pointcut注解声明频繁使用的切点表达式
     */
    @Pointcut("execution(* com.qin..te*(String,*))")
    public void methodPointCut() {

    }

    /**
     * 定义切入点,切入点为@MyTestAnnotation注解
     * 通过@Pointcut注解声明频繁使用的切点表达式
     */
    @Pointcut("@annotation(com.qin.test.annotation.MyTestAnnotation)")
    public void annotationPointCut() {

    }

    /**
     * @description 在连接点执行之前执行的通知
     * || :满足任意符合条件的连接点
     */
    @Before("methodPointCut() || annotationPointCut()")
    public void doBeforeTest() {
        System.out.println("Before......................");
    }

    /**
     * @description 在连接点执行之后执行的通知(返回通知和异常通知的异常)
     */
    @After("methodPointCut() || annotationPointCut()")
    public void doAfterTest() {
        System.out.println("After......................");
    }

    /**
     * @description 在连接点执行之后执行的通知(返回通知)
     *
     */
    @AfterReturning("methodPointCut() || annotationPointCut()")
    public void doAfterReturningTest() {
        System.out.println("AfterReturning......................");
    }

    /**
     * @description 在连接点执行之后执行的通知(异常通知)
     */
    @AfterThrowing("methodPointCut() || annotationPointCut()")
    public void doAfterThrowingTest() {
        System.out.println("AfterThrowing......................");
    }

    @Around("methodPointCut() || annotationPointCut()")
    public void doAroundTest(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Around proceed before......................");
        MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        MyTestAnnotation annotation = method.getAnnotation(MyTestAnnotation.class);
        System.out.println(annotation.name());
        System.out.println(annotation.value());
        proceedingJoinPoint.proceed();
        System.out.println("Around proceed after......................");
    }
}
3.1.execution表达式

<权限修饰符> <返回值> <包名> <类> <方法> <参数>

其中返回类型模式、方法名模式和参数模式时必须的,其它项都是可选的

表达式描述
public String com.qin.test.controller.TestController.test(…)匹配权限修饰符为public,返回值为String,在com.qin.test.controller包下的TestController类中方法名为test的任意方法参数的方法
public Object+ com.qin.test.controller.TestController.test(…)匹配权限修饰符为public,返回值为Object以及Object以及子类,但不包含void,在com.qin.test.controller包下的TestController类中方法名为test的任意方法参数的方法
public * com.qin…TestController.test(…)匹配权限修饰符为public,返回值为任意类型,在com.qin的子包下的TestController类中方法名为test的任意方法参数的方法
public * com.qin…TestController.te*(…)匹配权限修饰符为public,返回值为任意类型,在com.qin的子包下的TestController类中方法名为前缀为te的任意方法参数的方法
public * com.qin…TestController.*st(…)匹配权限修饰符为public,返回值为任意类型,在com.qin的子包下的TestController类中方法名为后缀为st的任意方法参数的方法
public * com.qin…TestController.*st(String,…)匹配权限修饰符为public,返回值为任意类型,在com.qin的子包下的TestController类中方法名为后缀为st,方法第一个参数为String类型的方法
public * com.qin…TestController.test(String,*)匹配权限修饰符为public,返回值为任意类型,在com.qin的子包下的TestController类中方法名为后缀为st,方法第一个参数为String类型的方法(仅有两个参数)
3.2.通知
注解描述
@Pointcut声明切点
@Before在连接点执行之前执行的通知
@After在连接点执行之后执行的通知(返回通知和异常通知的异常)
@AfterReturning在连接点执行之后执行的通知(返回通知)
@AfterThrowing在连接点执行之后执行的通知(异常通知)
@Around环绕通知:既可在执行目标方法之前增强动作,也可在执行目标方法之后织入增强的执行;可以控制目标方法是否执行以及如何执行(比如修改目标方法的参数)

4.执行顺序测试

4.1.测试类
package com.qin.test.controller;

import com.qin.test.annotation.MyTestAnnotation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 小枫
 * @version 1.0.0
 * @date 2020/10/13 21:20
 * @desciption TestController
 */
@RestController
public class TestController {

    /**
     * 方式一: execution表达式
     */
    @RequestMapping("/test")
    public void test(String name,Integer age) throws Exception {
        System.out.println("target method..................");
        //throw new Exception("eeeeeeeeee");
    }

    /**
     * 方式二: 注解
     */
    @RequestMapping("/test2")
    @MyTestAnnotation(value = "v",name = "n")
    public void anTest(String name,Integer age){
        System.out.println("target method..................");
    }
}
4.2.测试结果

1.抛出异常时

Around proceed before......................
Before......................
target method..................
After......................
AfterThrowing......................

2.正常执行

Around proceed before......................
Before......................
target method..................
Around proceed after......................
After......................
AfterReturning......................
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值