基于AspectJ注解方式实现AOP

 更新时间:2023年09月08日 10:56:41   作者:96岁对抗java  
这篇文章主要介绍了基于AspectJ注解方式实现AOP,使用AspectJ的注解可以更方便地编写和管理切面逻辑,而Spring AOP也是使用了AspectJ提供的注解来实现切面编程,需要的朋友可以参考下

基于AspectJ实现AOP(注解方式)

这里我们采用的是非完全注解方式

1. 创建类, 在类里面定义方法(连接点)

package com.ffyc.spring.aop;
//被增强的类(也就是被代理的类)
public class User {
    //被增强的方法(也就是被代理的方法)
    public void add(){
        System.out.println("add...");
    }
}

2. 创建增强类, 编写增强逻辑

  • 注意: 此时我们并没有给增强类添加注解来生成代理对象, 也没有配置通知(增强的逻辑)
package com.ffyc.spring.aop;
//增强类
public class UserProxy {
    //前置通知
    public void before(){
        System.out.println("before");
    }
    //这里还有后置通知, 异常通知, 环绕通知, 最终通知等, 现在逻辑先省略
}

3. 进行通知的配置

①: 在spring配置文件中, 开启注解扫描与开启注解自动生成代理对象

  • 注解扫描大家都知道: 就是componentScan
  • 注解自动生成代理对象是什么?
    • 就是开启了注解自动生成代理对象之后当SpringIOC容器扫描basePackages的时候如果扫描到某个类上面有@Aspect注解, 则会生成该类的代理对象放到SpringIOC容器中由SpringIOC容器管理
      • 所以@Aspect注解就是在增强(通知)类上添加的
<!--    开启组件扫描, 开启了组件扫描之后我们的spring容器就会在对应的base-package位置进行一个扫描-->
    <!--    注意: 其实我们的组件扫描也是可以通过使用注解的方式进行配置-->
        <context:component-scan base-package="com.ffyc.spring"></context:component-scan>
<!--    开启Aspectj自动生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

②: 使用注解创建User和UserProxy类的对象

  • 也就是让SpringIOC容器帮我们创建
  • 在User类和UserProxy类上加上@Component注解即可
package com.ffyc.spring.aop;
import org.springframework.stereotype.Component;
//被增强的类(也就是被代理的类)
@Component
public class User {
    //被增强的方法(也就是被代理的方法)
    public void add(){
        System.out.println("add...");
    }
}
package com.ffyc.spring.aop;
import org.springframework.stereotype.Component;
//增强类
@Component
public class UserProxy {
    //前置通知
    public void before(){
        System.out.println("before");
    }
}

③: 在增强类上面添加注解@Aspect

  • 这里注意: @Aspect注解要和@Component注解一起使用, 原因在最后
package com.ffyc.spring.aop;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
//增强类
@Component
@Aspect
public class UserProxy {
    //前置通知
    public void before(){
        System.out.println("before");
    }
}

4. 配置不同类型的通知

  • 在增强类里面, 在作为通知的方法上面添加对应的通知类型的注解, 并使用切入点表达式将对应的通知配置到某个切入点上
    • 这样Spring底层就会帮我们根据我们添加的注解来创建代理对象
package com.ffyc.spring.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//增强类
@Component
@Aspect
public class UserProxy {
    @Pointcut(value = "execution(* com.ffyc.spring.aop.User.add(..))")
    private void method(){
    }
    //前置通知
    @Before(value = "execution (* com.ffyc.spring.aop.User.add(..))")
    public void before(){
        System.out.println("before...");
    }
    @AfterReturning(value = "method()")
    public void afterReturning(){
        System.out.println("afterReturning...");
    }
    @After(value = "execution(* com.ffyc.spring.aop.User.add(..))")
    public void after(){
        System.out.println("after...");
    }
    @AfterThrowing(value = "method()")
    public void afterThrowing(){
        System.out.println("afterThrowing...");
    }
    @Around(value = "method()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前...");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后...");
    }
}
  • @PointCut注解用来创建一个切入点, 该注解的value属性(String类型)为切入点表达式
  • @Around, @Before, @After, @AfterReturning, @AfterThrowing注解的value属性(String类型)都为切入点表达式
  • @AfterThrowing针对的是被代理方法抛出异常, 如果异常在内部被解决, 那么并不会执行@AfterThrowing通知
  • 我们通过JVM的学习可以知道, 如果方法是通过异常结束(指抛出异常), 那么肯定就不是正常退出(return), 那么也就意味着@AfterReturning(后置通知), 和@AfterThrowing(异常通知)只能同时触发一个
  • @Around注解使用的时候要在参数位置预留一个ProceedingJoinPoint类型的参数, 最终会通过这个通知类构建一个被代理类的代理对象, 这个代理对象是由Spring帮我们创建的, 所以这个通知类也是Spring容器帮我们去扫描的, 对应的@Around注解标注的方法肯定也是由Spring帮我们调用的, 而Spring调用的方法我们可以在参数位置写一个形参, 这个时候Spring默认会对该参数类型进行一个自动装配(基于类型的自动装配), 这里就会由Spring帮我们装配一个ProceedingJoinPoint对象, 我们可以调用其中的proceed()方法, 调用proceed()方法就会执行切入点方法(被增强的方法)
    • ProceedingJoinPoint : 正在进行的连接点

5. 测试:

package com.ffyc.spring.aop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
    @Test
    public void testAop(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = applicationContext.getBean("user", User.class);
        System.out.println(user);
        user.add();
    }
}
  • 当我们调用user对象的add()方法的时候其实会执行代理对象的add()方法

各个通知的执行顺序:

环绕前[@Around(前)] --> 前置通知[@Before] --> 被增强方法(切入点) --> 环绕后(@Around(后)) --> 最终通知(@After) --> 后置通知[@AfterReturning] (或者异常通知[@AfterThrowing])

补充:

@Aspect注解为什么要和@Component注解一起使用, 按理将使用一个@Aspect注解不是就已经是由SpringIOC荣IQ创建代理对象并交由SpringIOC容器管理了?

**官方文档解释如下: **

You may register aspect classes as regular beans in your Spring XML configuration, or autodetect them through classpath scanning - just like any other Spring-managed bean. However, note that the @Aspect annotation is not sufficient for autodetection in the classpath: For that purpose, you need to add a separate @Component annotation (or alternatively a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).

翻译:

您可以在Spring XML配置中注册aspect类,或者通过类路径扫描自动检测它们,就像任何其他Spring管理bean一样。但是,请注意,@aspect注释对于在类路径中自动检测是不够的:为了达到这个目的,您需要添加一个单独的@component注解(或者根据Spring的组件扫描器的规则来定义一个定制的原型注解)

到此这篇关于基于AspectJ注解方式实现AOP的文章就介绍到这了,更多相关AspectJ实现AOP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于Mybatis-Plus拦截器实现MySQL数据加解密的示例代码

    基于Mybatis-Plus拦截器实现MySQL数据加解密的示例代码

    用户的一些敏感数据,例如手机号、邮箱、身份证等信息,在数据库以明文存储时会存在数据泄露的风险,因此需要进行加密,解密等功能,接下来本文就给大家介绍基于Mybatis-Plus拦截器实现MySQL数据加解密,需要的朋友可以参考下
    2023-07-07
  • SpringCloud的@RefreshScope 注解你了解吗

    SpringCloud的@RefreshScope 注解你了解吗

    这篇文章主要介绍了Spring Cloud @RefreshScope 原理及使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • mybatis 实现多条update同时执行

    mybatis 实现多条update同时执行

    这篇文章主要介绍了mybatis 实现多条update同时执行,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • JavaEE idea的smart tomcat插件使用

    JavaEE idea的smart tomcat插件使用

    这篇文章主要介绍了JavaEE idea的smart tomcat插件使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-09-09
  • idea2019.2安裝MybatisCodeHelper插件的超详细教程

    idea2019.2安裝MybatisCodeHelper插件的超详细教程

    这篇文章主要介绍了idea2019.2安裝MybatisCodeHelper插件的教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java线程之死锁

    java线程之死锁

    这篇文章主要介绍了Java线程之死锁,死锁是这样一种情形-多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止
    2022-05-05
  • 基于Ajax用户名验证、服务条款加载、验证码生成的实现方法

    基于Ajax用户名验证、服务条款加载、验证码生成的实现方法

    本篇文章对Ajax用户名验证、服务条款加载、验证码生成的实现方法,进行了详细的分析介绍。需要的朋友参考下
    2013-05-05
  • 对dbunit进行mybatis DAO层Excel单元测试(必看篇)

    对dbunit进行mybatis DAO层Excel单元测试(必看篇)

    下面小编就为大家带来一篇对dbunit进行mybatis DAO层Excel单元测试(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 详解Spring事务和事务传播机制

    详解Spring事务和事务传播机制

    本文主要介绍了MySQL中的事务以及如何在Spring框架中实现事务管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-12-12
  • Java网络编程之简单的服务端客户端应用实例

    Java网络编程之简单的服务端客户端应用实例

    这篇文章主要介绍了Java网络编程之简单的服务端客户端应用,以实例形式较为详细的分析了java网络编程的原理与服务器端客户端的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04

最新评论