基于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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合jersey的示例代码

    SpringBoot整合jersey的示例代码

    本篇文章主要介绍了SpringBoot整合jersey的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Java8深入学习系列(三)你可能忽略了的新特性

    Java8深入学习系列(三)你可能忽略了的新特性

    一提到Java 8就只能听到lambda,但这不过是其中的一个而已,Java 8还有许多新的特性,有一些功能强大的新类或者新的用法,还有一些功能则是早就应该加到Java里了,所以下面这篇文章主要给大家介绍了关于Java8中大家可能忽略了的一些新特性,需要的朋友可以参考下。
    2017-08-08
  • 分布式调度器之Spring Task 的使用详解

    分布式调度器之Spring Task 的使用详解

    SpringTask是Spring框架中用于任务调度的组件,通过简单的注解就能实现定时任务的创建和调度,可以通过配置线程池来实现,本文给大家介绍分布式调度器之Spring Task 的使用,感兴趣的朋友跟随小编一起看看吧
    2024-10-10
  • Spring实现动态数据源切换的方法总结

    Spring实现动态数据源切换的方法总结

    这篇文章主要为大家详细介绍了一种Spring实现动态数据源切换的方法,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-06-06
  • Java中ArrayList实现原理及基本方法

    Java中ArrayList实现原理及基本方法

    这篇文章主要介绍了Java中ArrayList实现原理及基本方法,ArrayList是开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,擅长随机访问元素,插入和删除较慢,需要的朋友可以参考下
    2023-08-08
  • 关于@Bean的使用方式

    关于@Bean的使用方式

    这篇文章主要介绍了关于@Bean的使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • 利用Sharding-Jdbc组件实现分表

    利用Sharding-Jdbc组件实现分表

    这篇文章主要为大家详细介绍了利用Sharding-Jdbc组件实现分表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • springboot2.x整合tkmapper的示例代码

    springboot2.x整合tkmapper的示例代码

    这篇文章主要介绍了springboot2.x整合tkmapper,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Java调用.dll文件的方法

    Java调用.dll文件的方法

    因为项目的需求,要在JAVA项目中调用Windows的Dll(动态链接库)文件,之前用Jni调用过C写的Dll文件,比较麻烦,这里不多说,网上也有很多这方面的文档。在网上找到一个开源的组件JNative,使用后感觉比较方便
    2013-04-04
  • java编写ftp下载工具

    java编写ftp下载工具

    本文给大家介绍的是如何一步步实现使用java编写FTP下载工具,而且是在Linux环境下使用javac编译的,在运行和编译上有些不同之处,有需要的小伙伴们参考下吧。
    2015-03-03

最新评论