Spring  AOP的两种使用方法

 更新时间:2022年08月11日 14:07:41   作者:青阳半雪​​​​​​​  
这篇文章主要介绍了Spring AOP的两种使用方法,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

前言

记录下 Spring AOP 的两种使用方式,不谈概念,只记录两种方式的使用例子

  • 注解方式
  • xml 配置方式

1 注解方式

1.1 声明目标类 UserDao 类

@Repository("userDao")
public class UserDao {

    public void addUser() {
        System.out.println("🚀 拦截的方法 addUser 开始执行");
    }
}

1.2 声明切面 AnnotationAspect 类

@Aspect
@Component
public class AnnotationAspect {

    // 定义切入点表达式, 使用一个返回值为 void、方法体为空的方法来命名切入点
    @Pointcut("execution(* com.fairy.springmvc.aspectj.annotation.*.*(..))")
    private void customPointCut(){}

    // 前置通知
    @Before("customPointCut()")
    public void myBefore(JoinPoint joinPoint){
        System.out.print("前置通知:模拟执行权限检查..,");
        System.out.print("目标类是:" + joinPoint.getTarget());
        System.out.println(",被植入增强处理的目标方法为:" + joinPoint.getSignature().getName());
    }

    // 后置通知
    @AfterReturning(value="customPointCut()")
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.print("后置通知:模拟记录日志..,");
        System.out.println("被植入增强处理的目标方法为:" + joinPoint.getSignature().getName());
    }

    /**
     * 环绕通知
     * ProceedingJoinPoint 是 JoinPoint的子接口,表示可执行目标方法
     * 1.必须是 Object 类型的返回值
     * 2.必须接收一个参数,类型为 ProceedingJoinPoint
     * 3.必须 throws Throwable
     */
    @Around("customPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        // 开始
        System.out.println("环绕开始:执行目标方法之前,模拟开启事务..,");
        // 执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        // 结束
        System.out.println("环绕结束:执行目标方法之后,模拟关闭事务..,");
        return obj;
    }

    /**
     * 异常通知处理
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value="customPointCut()",throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
        System.out.println("异常通知:出错了" + e.getMessage());
    }

    // 最终通知
    @After("customPointCut()")
    public void myAfter(){
        System.out.println("最终通知:模拟方法结束后释放资源..");
    }
}

1.3 声明配置

开启@AspectJ的注解配置方式,有两种方式

1 在 xml 文件,添加以下配置:

<!-- 启动基于注解的声明式 AspectJ 支持 -->
<aop:aspectj-autoproxy />

2 使用了 Java 代码风格的配置,则需使用 EnableAspectJAutoProxy 注解

示例如下

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.fairy.springmvc")
public class ApplicationConfig {
    ....
}

1.4 测试用例

public class TestCase {
    @Test
    public void testAnnotation() throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "spring-test.xml");

        // 从容器中获得内容
        UserDao userDao= (UserDao) applicationContext.getBean("userDao");
        // 执行方法
        userDao.addUser();
    }
}

运行结果如下:

环绕开始:执行目标方法之前,模拟开启事务..,
前置通知:模拟执行权限检查..,
    目标类是:com.fairy.springmvc.aspectj.annotation.UserDao@4a699efa,
    被植入增强处理的目标方法为:addUser
🚀 拦截的方法 addUser 开始执行
后置通知:模拟记录日志..,被植入增强处理的目标方法为:addUser
最终通知:模拟方法结束后释放资源..
环绕结束:执行目标方法之后,模拟关闭事务..,

通过输出结果看出,符合预期。

2 XML 配置方式

2.1 声明目标类 CompanyDao

@Repository("companyDao")
public class CompanyDao {

    public void addCompany() {
        System.out.println("🚀 真正的业务处理:add company 🚀");
    }

    public void exception() throws Exception {
        throw new Exception("业务异常了");
    }
}

2.2 声明切面拦截类 XmlAspect

@Component("xmlAspectConfig")
public class XmlAspect {

    public void printUnderscore() {
        System.out.println("------------------------------------------------");
    }

    /**
     * 在核心业务执行前执行,不能阻止核心业务的调用
     * @param joinPoint
     */
    public void beforeAdvice(JoinPoint joinPoint) {
        printUnderscore();
        System.out.println("1️⃣ 通知:beforeAdvice 执行开始");
        System.out.println("   执行核心业务逻辑前,可以做一些前置的安全性的检测等");
        System.out.println("   通知:beforeAdvice 执行结束");
        printUnderscore();
    }

    /**
     * 核心业务退出后,不管是正常结束还是异常退出,均执行此通知
     * @param joinPoint
     */
    public void afterAdvice(JoinPoint joinPoint) {
        printUnderscore();
        System.out.println("4️⃣ 通知:afterAdvice 执行开始");
        System.out.println("   此处可以对返回值做进一步的处理");
        System.out.println("   通知:afterAdvice 执行结束");
    }

    /**
     * 核心业务调用正常退出后,不管是否有返回值,只要是正常退出,都会执行此通知
     * @param joinPoint
     */
    public void afterReturningAdvice(JoinPoint joinPoint) {
        printUnderscore();
        System.out.println("2️⃣ 通知:afterReturningAdvice 执行开始");
        System.out.println("   此处可以对返回值做进一步处理");
        System.out.println("   通知:afterReturningAdvice 执行结束");
    }

    /**
     * 核心业务逻辑调用异常退出后,执行此通知,处理错误信息
     * @param e
     */
    public void afterThrowingAdvice(Exception e) {
        printUnderscore();
        System.out.println("3️⃣ 通知:afterThrowingAdvice 执行开始");
        System.out.println("   错误信息:" + e.getMessage());
        System.out.println("   此处意味着,在核心业务逻辑出错时,捕获异常,并可以做一些日志记录相关的操作");
    }

    /**
     * 手动控制调用核心业务逻辑,以及调用前和调用后的处理
     * @param pjp
     */
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        // 开始
        System.out.println("5️⃣ 环绕开始:执行目标方法之前");
        System.out.println("   此处可以做类似于 Before Advice 的事情");
        // 调用核心逻辑,执行当前目标方法
        Object obj = pjp.proceed();

        // 打印下划线
        printUnderscore();
        // 结束
        System.out.println("   此处可以做类似于 After Advice 的事情");
        System.out.println("5️⃣ 环绕结束:执行目标方法之后");
        return obj;
    }
}

2.3 声明 XML 配置

<!-- 基于 XML 文件的配置进行声明,注意和 aop:aspectj-autoproxy 的区别 -->
<aop:config proxy-target-class="true">

    <!-- 基于 aspect 配置一个完整的切面 -->
    <aop:aspect id="aspectXmlConfigExample" ref="xmlAspectConfig">
        <!-- 切点配置,可以配置多个切点 -->
        <aop:pointcut id="xmlPointCut"
                      expression="execution(* com.fairy.springmvc.aspectj.xml.CompanyDao.*(..))"/>
        <aop:after-returning method="afterReturningAdvice" pointcut-ref="xmlPointCut" />
        <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="xmlPointCut" throwing="e"/>
        <aop:after method="afterAdvice" pointcut-ref="xmlPointCut" />
        <aop:around method="aroundAdvice" pointcut-ref="xmlPointCut" />
        <aop:before method="beforeAdvice" pointcut-ref="xmlPointCut" />
    </aop:aspect>

</aop:config>

注意:

值得注意的是 around 与 before 和 after 的执行顺序。3 者的执行顺序取决于在 xml 中的配置顺序。

2.3 测试用例

public class TestCase {
    @Test
    public void testAnnotation() throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "spring-test.xml");

        CompanyDao companyDao = (CompanyDao) applicationContext.getBean("companyDao");
        companyDao.addCompany();
        // companyDao.exception();
    }

}

输出结果如下:

-------------------------------
5️⃣ 环绕开始:执行目标方法之前
   此处可以做类似于 Before Advice 的事情
------------------------------------------------
1️⃣ 通知:beforeAdvice 执行开始
   执行核心业务逻辑前,可以做一些前置的安全性的检测等
   通知:beforeAdvice 执行结束
------------------------------------------------
🚀 真正的业务处理:add company 🚀
------------------------------------------------
2️⃣ 通知:afterReturningAdvice 执行开始
   此处可以对返回值做进一步处理
   通知:afterReturningAdvice 执行结束
------------------------------------------------
4️⃣ 通知:afterAdvice 执行开始
   此处可以对返回值做进一步的处理
   通知:afterAdvice 执行结束
------------------------------------------------
   此处可以做类似于 After Advice 的事情
5️⃣ 环绕结束:执行目标方法之后

结果符合预期。

到此这篇关于Spring  AOP 的两种使用方法的文章就介绍到这了,更多相关Spring  AOP 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决idea中maven项目打包成jar报错:没有主清单属性的问题

    解决idea中maven项目打包成jar报错:没有主清单属性的问题

    这篇文章主要给大家分享了idea中maven项目打包成jar,报错没有主清单属性解决方法,文中有详细的解决方法,如果又遇到同样问题的朋友可以参考一下本文
    2023-09-09
  • Spring:如何使用枚举参数

    Spring:如何使用枚举参数

    这篇文章主要介绍了springboot枚举类型传递的步骤,帮助大家更好的理解和学习使用springboot,感兴趣的朋友可以了解下,希望能给你带来帮助
    2021-08-08
  • springboot配置resilience4j全过程

    springboot配置resilience4j全过程

    这篇文章主要介绍了springboot配置resilience4j全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • idea gradle项目复制依赖小技巧(推荐)

    idea gradle项目复制依赖小技巧(推荐)

    这篇文章主要介绍了idea gradle项目复制依赖小技巧,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • SpringBoot使用JDBC获取相关的数据方法

    SpringBoot使用JDBC获取相关的数据方法

    这篇文章主要介绍了SpringBoot使用JDBC获取相关的数据方法,JDBC与数据库建立连接、发送 操作数据库的语句并处理结果,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • SpringBoot中的Bean注入问题

    SpringBoot中的Bean注入问题

    SpringBoot开发中,Bean注入是关键,涉及构造函数注入、Setter注入和字段注入等方法,常见问题包括Bean未找到、循环依赖、多个实现注入等,推荐使用构造函数注入以增强代码测试性和维护性,并关注Bean的生命周期和作用域
    2024-09-09
  • 一问详解SpringBoot配置文件优先级

    一问详解SpringBoot配置文件优先级

    在SpringBoot项目当中,我们要想配置一个属性,可以通过这三种方式当中的任意一种来配置都可以,那么优先级怎么算,本文主要介绍了一问详解SpringBoot配置文件优先级,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Idea跑的项目没问题将程序install成jar包运行报错空指针的问题

    Idea跑的项目没问题将程序install成jar包运行报错空指针的问题

    这篇文章主要介绍了Idea跑的项目没问题,将程序install成jar包运行报错空指针的问题,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • 用SpringBoot框架来接收multipart/form-data文件方式

    用SpringBoot框架来接收multipart/form-data文件方式

    这篇文章主要介绍了用SpringBoot框架来接收multipart/form-data文件方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java实现AOP代理的三种方式详解

    Java实现AOP代理的三种方式详解

    AOP是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善。本文将用Java实现AOP代理的三种方式,需要的可以参考一下
    2022-07-07

最新评论