spring boot AOP练习 @Aspect

2023-11-03

spring boot AOP练习 @Aspect

环境

		<!--  主要依赖     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

开启配置

/**
 * @author smxr
 * @date 2020/11/19
 * @time 11:11
 * @EnableAspectJAutoProxy(proxyTargetClass = true)
 * 这个为true时,则会使用 cglib 的动态代理方式;缺点:拓展类的实例用final修饰时,则无法进行织入
 * 默认使用的是jdk动态代理; 缺点:会有一点影响性能
 * 12/23:默认(proxyTargetClass = true不使用)时,当动态代理的对象是接口时,会使用jdk动态代理,如果对象是Class时使用cglib动态代理
 */
@Configuration
@EnableAspectJAutoProxy
public class ConfigBean {

    @Conditional(UserConditional.class)
    @Bean
    public User user(){
        System.out.println("张三加载中...........");
        User user = new User();
        user.setUserName("张三");
        return user;
    }
    @Conditional(UserConditional2.class)
    @Bean
    public User user2(){
        System.out.println("李四加载中...........");
        User user = new User();
        user.setUserName("李四");
        return user;
    }
}

在这里插入图片描述项目结构

@Aspect 切面类

/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:33
 */
@Aspect
@Component
public class AspectUserService {
//    @Pointcut("execution( public * com.redis.service.impl.UserServiceImpl.sleep(..))")
    private void PointCut(){}
    @Before("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepBefore(JoinPoint joinPoint){
      //  System.out.println(joinPoint.toString());//输出结果:execution(void com.redis.service.impl.UserServiceImpl.sleep())
      // MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
       //String[] params = methodSignature.getParameterNames();// 获取参数名称
       //Object[] args = joinPoint.getArgs();// 获取参数值
        System.out.println("前置拦截开始了");//2
    }
    @After("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepAfter(JoinPoint joinPoint){
        System.out.println("后置拦截开始了");//4
    }
    @AfterReturning("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepAfterReturning(JoinPoint joinPoint){
        System.out.println("完成拦截开始了");//3
    }
    @AfterThrowing("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleep(JoinPoint joinPoint){
        System.out.println("异常拦截开始了");
    }
    @Around("execution(public * com.redis.service.UserService.sleep(..))")
    public void sleepAround(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("前置环绕:运行......");//1
            proceedingJoinPoint.proceed();
            System.out.println("后置环绕:运行......");//5
        } catch (Throwable throwable) {
            System.out.println("环绕:运行异常......");
        }
    }
}

相关接口和实现类

/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:20
 */
public interface UserService {
    public void eat();
    public void sleep();
    public void corporate_slave();
    public void speak(User user);
}

import com.redis.pojo.User;
import com.redis.service.UserService;
import org.springframework.stereotype.Service;

/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:25
 */
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void eat() {
        System.out.println("要去吃饭了......");
    }

    @Override
    public void sleep() {
        System.out.println("终于到了放松的时候了........");
    }

    @Override
    public void corporate_slave() {
        System.out.println("要去工作了.........");
    }

    @Override
    public void speak(User user) {
        System.out.println(user.getUserName()+"说:.......");
    }
}

测试及结果

@SpringBootTest
class SpringbootRedisApplicationTests {
    @Autowired
    UserServiceImpl userService;
    @Test
    void AOPTest(){
        userService.sleep();
    }
     -----------------------------------------------
前置环绕:运行......
前置拦截开始了
终于到了放松的时候了........
完成拦截开始了
后置拦截开始了
后置环绕:运行......

不知道有没有错,反正跑出来的顺序就这样的.

切面有参的AOP练习

AspectUserService.class

    //不关注 参数  
    @Around("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("前置环绕:运行......");
            proceedingJoinPoint.proceed();
            System.out.println("后置环绕:运行......");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    //
    /*
    * 关注 参数
    * && args(user) 指定参数;要传入的参数
    * && bean(userServiceImpl) 指定要使用的容器组件名;即这个指定的(userServiceImpl)组件bean去调用,才能生效.
    */
    @Around("execution(public * com.redis.service.UserService.speak(..)) && args(user)")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint,User user){
        try {
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!如果你大意了,就没有闪了");
            }else if (user.getUserAge()>69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!");
            }else {
                System.out.println(user.getUserName()+"的前置环绕即将说话:请注意听讲");
            }
            proceedingJoinPoint.proceed();
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志发言完成,恭喜大家获取技能闪电五连变");
            }else {
                System.out.println(user.getUserName()+"的后置环绕完成!");
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

测试代码

    @Test
    void AOPTest1(){
        User user3 = new User();
        user3.setUserName("马老师");
        user3.setUserAge(69);
        userService.speak(user3);
        System.out.println("----------------分界线--------------------");
        User user4 = new User();
        user4.setUserName("老马");
        user4.setUserAge(80);
        userService.speak(user4);
    }
前置环绕:运行......
69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
马老师说:.......
69老同志发言完成,恭喜大家获取技能闪电五连变
后置环绕:运行......
----------------分界线--------------------
前置环绕:运行......
80老同志即将发言,请注意听讲!
老马说:.......
老马的后置环绕完成!
后置环绕:运行......
    //要注意指定的 && bean(userServiceImpl)  否则重新注入一个新的userServiceImpl2 是不能调用的
    @Autowired
    UserServiceImpl userService;

还是看下案例吧!
新注入一个userService2

@Configuration
@EnableAspectJAutoProxy
public class ConfigBean {

    @Conditional(UserConditional.class)
    @Bean
    public User user(){
        System.out.println("张三加载中...........");
        User user = new User();
        user.setUserName("张三");
        return user;
    }
    @Conditional(UserConditional2.class)
    @Bean
    public User user2(){
        System.out.println("李四加载中...........");
        User user = new User();
        user.setUserName("李四");
        return user;
    }
    @Bean
    public UserServiceImpl userService2(){
        UserServiceImpl userService2 = new UserServiceImpl();
        return userService2;
    }
}

原来的service 声明bean名字


/**
 * @author smxr
 * @date 2020/11/23
 * @time 10:25
 */
@Service(value = "userService")
public class UserServiceImpl implements UserService {
    @Override
    public void eat() {
        System.out.println("要去吃饭了......");
    }

    @Override
    public void sleep() {
        System.out.println("终于到了放松的时候了........");
    }

    @Override
    public void corporate_slave() {
        System.out.println("要去工作了.........");
    }

    @Override
    public void speak(User user) {
        System.out.println(user.getUserName()+"说:.......");
    }
}

测试及结果

@SpringBootTest
class SpringbootRedisApplicationTests {
    @Autowired
    UserServiceImpl userService;
    @Autowired
    UserServiceImpl userService2;

    @Test
    void AOPTest1(){
        User user3 = new User();
        user3.setUserName("马老师");
        user3.setUserAge(69);
        userService.speak(user3);
        System.out.println("----------------分界线--------------------");
        User user4 = new User();
        user4.setUserName("老马");
        user4.setUserAge(80);
        userService2.speak(user4);
    }

}

69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
马老师说:.......
69老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
老马说:.......

上面的我把 无参的那个给注释掉了, 下面解开注释在跑一次

    //不关注 参数
    @Around("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("前置环绕:运行......");
            proceedingJoinPoint.proceed();
            System.out.println("后置环绕:运行......");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    //
    /*
    * 关注 参数
    * && args(user) 指定参数;要传入的参数
    * && bean(userServiceImpl) 指定要使用的容器组件名;即这个指定的(userServiceImpl)组件bean去调用,才能生效.
    */
    @Around("execution(public * com.redis.service.UserService.speak(..)) && args(user)&& bean(userService)")
    public void speakAround(ProceedingJoinPoint proceedingJoinPoint,User user){
        try {
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!如果你大意了,就没有闪了");
            }else if (user.getUserAge()>69){
                System.out.println(user.getUserAge()+"老同志即将发言,请注意听讲!");
            }else {
                System.out.println(user.getUserName()+"的前置环绕即将说话:请注意听讲");
            }
            proceedingJoinPoint.proceed();
            if (user.getUserAge()==69){
                System.out.println(user.getUserAge()+"老同志发言完成,恭喜大家获取技能闪电五连变");
            }else {
                System.out.println(user.getUserName()+"的后置环绕完成!");
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

测试和结果

69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
前置环绕:运行......
马老师说:.......
后置环绕:运行......
69老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
前置环绕:运行......
老马说:.......
后置环绕:运行......

看代码来说如果指定了参数(&&args)和指定了运行的bean(&&bean) ,那么这个切面只有相应的bean才能被调用;
没有指定参数(&&args)和运行的bean(&&bean),那么只要这个实例被调用就,都会执行切面;
如果两个同时存在,那么都会被执行,有参的优先级较高,先执行将包含无参的;

挺好奇的,上面的代码他们的@Before,@After,@AfterReturning,他们什么时候执行?

先改下代码,新增

    @Before("execution(public * com.redis.service.UserService.speak(..))")
    public void speakBefore(JoinPoint joinPoint){
        System.out.println("前置拦截开始了");
    }
    @After("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAfter(JoinPoint joinPoint){
        System.out.println("后置拦截开始了");
    }
    @AfterReturning("execution(public * com.redis.service.UserService.speak(..))")
    public void speakAfterReturning(JoinPoint joinPoint){
        System.out.println("完成拦截开始了");
    }

测试及结果

    @Test
    void AOPTest1(){
        User user3 = new User();
        user3.setUserName("马老师");
        user3.setUserAge(69);
        userService.speak(user3);
        System.out.println("----------------分界线--------------------");
        User user4 = new User();
        user4.setUserName("老马");
        user4.setUserAge(80);
        userService2.speak(user4);
    }

前置环绕:运行......
69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
前置拦截开始了
马老师说:.......
完成拦截开始了
后置拦截开始了
69老同志发言完成,恭喜大家获取技能闪电五连变
后置环绕:运行......
----------------分界线--------------------
前置环绕:运行......
前置拦截开始了
老马说:.......
完成拦截开始了
后置拦截开始了
后置环绕:运行......

阿狸! 什么鬼 ? 我注释掉新加在跑一次

前置环绕:运行......
69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
马老师说:.......
69老同志发言完成,恭喜大家获取技能闪电五连变
后置环绕:运行......
----------------分界线--------------------
前置环绕:运行......
老马说:.......
后置环绕:运行......

干掉代码在跑,加上代码在跑

69老同志即将发言,请注意听讲!如果你大意了,就没有闪了
前置环绕:运行......
前置拦截开始了
马老师说:.......
完成拦截开始了
后置拦截开始了
后置环绕:运行......
69老同志发言完成,恭喜大家获取技能闪电五连变
----------------分界线--------------------
前置环绕:运行......
前置拦截开始了
老马说:.......
完成拦截开始了
后置拦截开始了
后置环绕:运行......

反正挺好玩的! 我也没搞清楚 倒是是无参的先还是有参的先,
或者它们本来就是不分先后的,也许就不能一块用;
不过其他三个倒是挺正常的;先@Before,在@AfterReturning,最后@After

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring boot AOP练习 @Aspect 的相关文章

  • XSD 验证错误:在 web.xml 中找不到 TagLib 标记

    我详细显示错误如下 cvc complex type 2 4 a 发现以元素开头的无效内容 taglib One of http java sun com xml ns javaee 描述 http java sun com xml ns
  • Jackson反序列化SNS消息错误MismatchedInputException

    我正在编写一个通过 SNS HTTP 请求处理来自 Amazon Simple Email Service 的回调的功能 我想将亚马逊提供的消息解析为本地对象结构 问题是 SNS 将 JSON 消息包装成字符串 并且 Jackson 无法解
  • Firebase 实时数据库 .info/connected 本应为 True 时为 False

    我有一个 Android 服务 它的调用地址为onCreate FirebaseDatabase database FirebaseDatabase getInstance database getReference info connec
  • Java 延迟/等待

    如何将 while 循环延迟到 1 秒间隔 而不减慢其运行的整个代码 计算机的速度到一秒延迟 只是一个小循环 Thread sleep 1000 do nothing for 1000 miliseconds 1 second
  • 将双精度转换为二进制表示形式?

    我尝试将双精度数转换为其二进制表示形式 但使用此Long toBinaryString Double doubleToRawLongBits d 没有帮助 因为我有大量数字 Long 无法存储它们 即2 900 Long toBinaryS
  • 匿名类*总是*维护对其封闭实例的引用吗?

    我正在处理一些代码 其中一个对象 foo 正在创建另一个对象 对象 bar 并将其传递给Callable 之后 foo 将返回 bar 然后我希望 foo 变得无法访问 即 可用于 垃圾收集 我最初的想法是创建Callable匿名 例如 c
  • 如何将 Struts 2 与 Velocity 和 Tiles 结合使用

    有人能够获得与 struts 2 一起使用的速度和图块吗 我在网上查找示例或教程时遇到一些问题 从我从邮件列表中收集到的信息来看 这似乎根本不可能 但邮件已经很旧了 https struts apache org docs tiles pl
  • HashMap何时以及如何将桶从链表转换为红黑树? [复制]

    这个问题在这里已经有答案了 我正在研究 java 8 功能 发现当存储桶上的条目集数量增加时 哈希图使用红黑树而不是链表 但是 这是否不需要密钥是可比较的或存在某种密钥排序以及这是如何工作的 这种转变何时真正发生以及如何发生 当有at le
  • 将 Java 3D 坐标转换为 2D 屏幕坐标

    我正在使用一个名为 Walrus 的 Java 3D 应用程序 该应用程序用于显示有向图 该代码已经具有突出显示节点并在给定其屏幕坐标的情况下在图形中相邻绘制标签的功能 旋转屏幕后 该节点不再突出显示 我所拥有的是 3D 中的节点坐标 我需
  • 在类路径中使用通配符调用 java 失败

    我当前目录中有一些 jar 它们都需要位于类路径中 因此我想对类路径使用通配符约定 命令行是 java exe classpath org python util jython args 但是我收到这个错误 Exception in thr
  • Java文本输出中的UTF-8编码问题

    我一直致力于测试高棉语 Unicode Wordbreaker 的各种解决方案 高棉语单词之间没有空格 这使得拼写检查和语法检查变得困难 以及从旧高棉语转换为高棉语 Unicode 我得到了一些源代码 现在在线 http www white
  • 如何将空字符串序列化为单个空标签?

    我使用 Simple XML 框架序列化此类 Root public class HowToRenderEmptyTag Element required false private String nullString 我想得到
  • Jackson 中没有注释的多态反序列化

    我有一个CloudEvent
  • 如何在不打开浏览器的情况下查看 Android 应用程序中的网页?

    嘿 我正在开发一个 Android 应用程序 我想连接到该应用程序内的网络 不过 我在某种程度上尝试过 WebView 但它在我的目录中显示的文件很好 但当连接到 google com 时 它显示错误 然后我添加了这个文件
  • 码头无故停止

    我需要经验丰富的码头用户的建议 我在负载均衡器 亚马逊云 后面维护着 2 台 Linux 机器 使用 Jetty 9 0 3 有时我的 Jetty 容器会被 Thread 2 无故关闭 同时地 显示以下日志并且容器无故停止 没有错误 没有例
  • 在JAVA中将数据写入.txt文件?

    我想知道是否是在JAVA中将计算的数据写入文本文件 我的 JAVA 代码是一个基于 GUI 的 gpa 计算器 我只想添加一个 JButton 和 ActionListener 它将类名 GPA 点和计算出的 GPA 写入 txt 文件 这
  • 启动 Firefox 并等待其关闭

    Question 我想启动 Firefox 网络浏览器作为访问特定网站的过程 然后等到它关闭 一种特殊情况是浏览器可能已经打开并正在运行 因为用户可能已经访问过某个网站 在这种情况下 浏览器可能会在现有窗口中打开一个新选项卡 并且新启动的进
  • Java 8 流过滤器 - 基于排序的更新

    我正在尝试对过滤器中的字段进行排序 输入文件 样本记录 DocumentList Document id 5975ff00a213745b5e1a8ed9 u id mailboxcontent id 5975ff00a213745b5e1
  • 在Java中将32bpp图像转换为16bpp图像

    如何使用 Java 库将 32bpp 图像 ARGB 转换为 16bpp 图像 ARGB 出于我的好奇 在像素级别 这种转换有什么作用 如果我有一个保存像素值 包含所有通道 的 int 值 那么在转换发生后该 int 会有什么不同 32 位
  • Swing:如何创建事件并将其分派给组件?

    我需要将一些事件发送到 Swing 中的组件 因此它的处理方式就像任何用户生成的标准 Swing 事件一样 基本上 类似于宏记录器 然后是 JEditorPane 的执行器 但我需要对生成的事件有更多的控制 所以 假设我有一个编辑 我想 捕

随机推荐

  • 网络原理之初识

    目录 网络发展背景 独立模式 网络互联 局域网 广域网 网络通信基础 IP地址 端口号 协议 协议分层 OSI七层网络模型 TCP IP五层 四层 网络模型 物理层 数据链路层 网络层 传输层 应用层 封装和分用 网络发展背景 独立模式 独
  • Tensorflow 摄像头物体实时识别

    官方源码提供了图片的检测 但是实用性不高 所以对源码进行了修改 使用笔记本自带摄像头或者usb摄像头进行实时检测 第二张是摄像头实时物体识别 参考源 视频 https www youtube com watch v COlbP62 B U
  • 第41步 深度学习图像识别:Efficientnet建模(Tensorflow)

    一 写在前面 1 Efficientnet EfficientNet是Google在2019年提出的一种新的卷积神经网络架构 主要目标是提高模型的效率 即在保持或提高模型性能的同时 尽可能地降低模型的复杂性和计算需求 EfficientNe
  • 如何快速提高个人的计算机水平,如何进一步提高计算机水平

    文章 如何进一步提高计算机水平 周老师 您好 我是一名中学信息技术教师 我现在想进一步提高自己计算机专业方面的知识和能力 不知如何去做 我不是计算机专业毕业的 从事信息技术课程教学已两年 我对简单的Office 2000应用及计算机基本操作
  • 通过添加Access-Control-Allow-Origin首部字段,解决flask跨域问题

    今天在使用swagger测试接口的时候出现无法获取返回的问题 TypeError Origin http 10 8 15 49 18081 is not allowed by Access Control Allow Origin 查看日志
  • 树莓派接多个USB摄像头,使用opencv打开指定的某一个摄像头

    问题描述 在树莓派上使用多个USB摄像头时 如何确定各个摄像头所对应的id 比如 当有两个摄像头时 我尝试一个为cv2 VideoCapture 0 一个为cv2 VideoCapture 1 通过看捕获的图像 可以确定各摄像头的id 但这
  • attachInterrupt()函数

    attachInterrupt 函数介绍 attachInterrupt 函数是用于为Arduino开发板设置和执行ISR 中断服务程序 用的 ISR 中断服务程序 顾名思义就是中断Arduino当前正在处理的事情而优先去执行中断服务程序
  • 【CF补题】Codeforces Round #784 (Div. 4)C++代码

    A include
  • idea连接kerberos认证的hive

    其实用dbeaver连接hive就可以了 但是呢 idea也有这个功能 本着研究下的想法就试试 结果最后成功了 最后记录下 参考文章 感觉不太行 PyCharm idea通过插件database连接带Kerberos的hive 不饿同学的博
  • 服装商品销售数据分析

    一 分析背景和数据来源 随着电商的快速发展 人们的购物行为占比也快速增加 作为电商卖家为了获取更多的用户并提升店铺销售量 可以结合产品销售情况和用户情况进行分析 得到有价值的信息 规划自己的销售策略 本文以淘宝天猫上服装商品购买情况数据为例
  • Qt绘制雷达图(卫星轨迹图)

    效果图 功能 使用QPainter绘制 雷达图主要包括 同心圆 十字架 刻度 不同颜色的圆圈 可以设置卫星的俯仰角 方位角 程序采用系统与卫星的结合 多种系统 n个卫星数据 进行显示 可自行搭配数据结构 监测卫星活动状态 定时清理无数据卫星
  • 数值概率算法

    基本概念 计算定积分 rand和srand 在解决设计问题时 有时会用到概率算法 概率算法允许在执行过程中随机的选择下一步的计算步骤 又是可使算法大大降低复杂度 提高算法效率 但有时也可能得不到问题的全部答案 基本概念 概率算法大致分为4类
  • 【Python】list.append()字典在for循环中数据覆盖的分析与解决

    问题 预期打印出来的list为 num 0 num 1 num 2 结果为 num 2 num 2 num 2 list dictionary num for i in range 3 dictionary num i list appen
  • 安装bootstrap

    导入软件源的 GPG key 并且添加 Yarn APT 软件源到你的系统 curl sS https dl yarnpkg com debian pubkey gpg sudo apt key add echo deb https dl
  • USB

    usb有主从设备之分 主设备有 pc 现在市面上的那些插u disk即可播放mp3的 mp3 之类的 usb 信号是差分信号 信号线为D D 在usb host 端 D D 各接一个15kohm 的下拉电阻 而在usb device端 这时
  • ue打开服务器文件速度很慢,看完大牛这篇文章,再遇到服务器反映慢的情况就不怕了...

    最近服务器反映很慢 查看服务器上的应用程序经常出现超时等等 而且还有时候出现卡死的情况 经过发现服务器I O压力很大 压力来自硬盘的I O访问已经达到100 最后原因是线上业务代码同一时间写入导致服务器硬盘I O爆表了 我这里纪录一下为了方
  • Hadoop集群搭建记录

    本文目录 写在前面 step1 安装openssh server step2 ssh文件夹的创建及生成密钥文件 step3 传送该文件 step4 slave1 slave2节点操作 step5 所有节点最终配置 免密登录成功 写在前面 本
  • 原来早就有java代码规范

    happy 最近几天 研究代码规范 想给给公司制定一个代码规范 公司很小 目前还没有代码规范 这个东西很烦人 也很难产生作用 小公司一般不采用吧 但现在为了提高代码质量 也就需要考虑了 今天 发现早在1997年 SUN公司就制定了java代
  • logit回归模型_混合logit模型(随机参数模型)的STATA应用及结果解读

    选择实验获得的数据主要通过离散选择模型来完成 离散选择模型中 最主要的是logit模型 之前已经介绍了二项logit模型回归的STATA实现 有修改 多项logit模型详解 多项logit模型回归系数解读 多项logit模型回归的检验 继续
  • spring boot AOP练习 @Aspect

    spring boot AOP练习 Aspect 环境