深入理解Spring AOP的工作流程

文章目录

    • 引言
    • 什么是AOP?
    • Spring AOP的工作原理
      • 1. JDK动态代理
      • 2. CGLIB代理
    • Spring AOP的注解方式
      • @Aspect注解
      • @EnableAspectJAutoProxy注解
    • Spring AOP的工作流程
    • 拓展应用
      • 1. 自定义注解
      • 2. 异常处理
      • 3. 切面优先级
    • 结论

在这里插入图片描述

🎉深入理解Spring AOP的工作流程


  • ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹
  • ✨博客主页:IT·陈寒的博客
  • 🎈该系列文章专栏:架构设计
  • 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习
  • 🍹文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️

引言

在现代的软件开发中,面向切面编程(AOP)是一种重要的编程范式,用于解耦业务逻辑和横切关注点(cross-cutting concerns)。Spring框架提供了强大而灵活的AOP支持,通过代理机制实现横切关注点的注入。本文将深入探讨Spring AOP的工作流程,帮助读者更好地理解其原理和应用。

什么是AOP?

AOP是一种编程思想,通过在程序中间插入横切关注点,将系统划分为核心业务逻辑和横切关注点两部分。横切关注点包括日志记录、事务管理、安全控制等与核心业务逻辑无关但又必须在程序中执行的功能。AOP通过将这些横切关注点与核心业务逻辑分离,提高了代码的模块化和可维护性。

Spring AOP通过代理机制实现横切关注点的注入,其中代理对象负责执行横切逻辑。在Spring AOP中,常见的横切关注点包括日志记录、性能监控、事务管理等。

Spring AOP的工作原理

Spring AOP基于代理模式,主要通过两种方式实现:

  1. JDK动态代理: 基于接口的代理机制,使用java.lang.reflect.Proxy类生成代理对象。

  2. CGLIB代理: 基于类的代理机制,使用CGLIB库生成代理对象。

1. JDK动态代理

JDK动态代理要求目标类实现一个或多个接口,代理对象实现这些接口并委托给目标对象。以下是一个简单的例子:

public interface UserService {void addUser(String username, String password);
}public class UserServiceImpl implements UserService {@Overridepublic void addUser(String username, String password) {// 实际业务逻辑System.out.println("User added: " + username);}
}public class LogAspect implements InvocationHandler {private Object target;public LogAspect(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Log: Method " + method.getName() + " is invoked");Object result = method.invoke(target, args);return result;}
}// 使用代理
public class Main {public static void main(String[] args) {UserService target = new UserServiceImpl();InvocationHandler handler = new LogAspect(target);UserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);proxy.addUser("John", "123456");}
}

2. CGLIB代理

CGLIB代理不要求目标类实现接口,代理对象继承目标对象。以下是一个简单的例子:

public class UserService {public void addUser(String username, String password) {// 实际业务逻辑System.out.println("User added: " + username);}
}public class LogAspect implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Log: Method " + method.getName() + " is invoked");Object result = proxy.invokeSuper(obj, args);return result;}
}// 使用代理
public class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);enhancer.setCallback(new LogAspect());UserService proxy = (UserService) enhancer.create();proxy.addUser("John", "123456");}
}

Spring AOP的注解方式

除了基于XML的配置方式,Spring AOP还支持使用注解的方式配置切面。

@Aspect注解

在使用注解方式配置AOP时,首先需要使用@Aspect注解声明一个切面类。该类包含了多个切点和通知,用于定义横切逻辑。

@Aspect
@Component
public class LogAspect {@Pointcut("execution(* com.example.service.*.*(..))")public void pointcut() {}@Before("pointcut()")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Log: Before " + joinPoint.getSignature().getName());}@After("pointcut()")public void afterAdvice(JoinPoint joinPoint) {System.out.println("Log: After " + joinPoint.getSignature().getName());}
}

上述例子中,@Pointcut注解定义了一个切点,表示匹配com.example.service包下所有类的所有方法。@Before@After注解分别表示前置通知和后置通知。

@EnableAspectJAutoProxy注解

在Spring Boot中,还需要在配置类上使用@EnableAspectJAutoProxy注解开启自动代理功能。该注解告诉Spring Boot启用AspectJ自动代理。

@SpringBootApplication
@EnableAspectJAutoProxy
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

Spring AOP的工作流程

Spring AOP的工作流程可以概括为以下几个步骤:

  1. 定义切面: 创建一个Java类,并在类上使用@Aspect注解声明为切面类。在切面类中定义切点和通知。

  2. 配置通知: 使用@Before@After等注解配置通知,定义横切逻辑。

  3. 激活切面: 在配置类上使用@EnableAspectJAutoProxy注解激活切面。

  4. 容器初始化: Spring容器启动时,会扫描并解析所有标有@Aspect注解的类。

  5. 生成代理对象: 对于被代理的目标对象,Spring会根据切面定义生成代理对象。代理对象包含了横切逻辑。

  6. 执行横切逻辑: 在目标方法执行前、后或异常时,执行横切逻辑。

拓展应用

Spring AOP的应用远不止上述简单例子所示,还可以结合更复杂的切面和通知,实现更丰富的横切逻辑。以下是一些拓展应用的示例:

1. 自定义注解

可以使用自定义注解来标记切点,让代码更具可读性。例如,定义一个@Log注解,标记需要记录日志的方法。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {String value() default "";
}

然后,在切面类中使用@Around注解拦截被@Log注解标记的方法。

@Aspect
@Component
public class LogAspect {@Around("@annotation(com.example.annotation.Log)")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Log: Method " + joinPoint.getSignature().getName() + " is invoked");Object result = joinPoint.proceed();return result;}
}

2. 异常处理

通过@AfterThrowing注解可以实现异常处理逻辑,记录异常信息或进行其他处理。

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {System.out.println("Exception: " + ex.getMessage());
}

3. 切面优先级

通过@Order注解可以指定切面的优先级,数字越小,优先级越高。

@Aspect
@Component
@Order(1)
public class LogAspect {// ...
}

在这里插入图片描述

结论

Spring AOP是Spring框架中一个重要的组件,通过代理机制实现横切关注点的注入。本文深入介绍了Spring AOP的工作原理,包括基于JDK动态代理和CGLIB代理的实现方式,以及使用注解配置AOP的方法。通过理解Spring AOP的工作流程,我们能更好地应用和拓展AOP,提高代码的模块化和可维护性。希望本文能够帮助读者更深入地理解和应用Spring AOP。


🧸结尾 ❤️ 感谢您的支持和鼓励! 😊🙏
📜您可能感兴趣的内容:

  • 【Java面试技巧】Java面试八股文 - 掌握面试必备知识(目录篇)
  • 【Java学习路线】2023年完整版Java学习路线图
  • 【AIGC人工智能】Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么
  • 【Java实战项目】SpringBoot+SSM实战:打造高效便捷的企业级Java外卖订购系统
  • 【数据结构学习】从零起步:学习数据结构的完整路径

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/211900.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

柯桥生活日语学习,打工人的日语你会吗?

打工人在日语里有几种说法: アルバイト 这是最常用的称呼,直接对应中文的“打工”。 例句: 学生の頃はスーパーでアルバイトをしていた。(我学生时代在超市打过工。) バイト これはアルバイトの略称でよく使われる。(这是アルバイト的简称,也很常用。) 例句: バイト先が決…

Modbus故障码速查手册(故障码含义、分析原因、详细解读)

Modbus故障码速查手册 文章目录 Modbus故障码速查手册引言故障码表故障详解0x01 IllegalFunction0x02 IllegalDataAddress0x03 IllegalDataValue0x04 SlaveDeviceFailure0x05 Acknowledge0x06 SlaveDeviceBusy0x08 MemoryParityError0x0A GatewayPathUnavailable0x0B GatewayTa…

9.3 Windows驱动开发:内核解析PE结构节表

在笔者上一篇文章《内核解析PE结构导出表》介绍了如何解析内存导出表结构,本章将继续延申实现解析PE结构的PE头,PE节表等数据,总体而言内核中解析PE结构与应用层没什么不同,在上一篇文章中LyShark封装实现了KernelMapFile()内存映…

脉冲幅度调制信号的功率谱计算

本篇文章是博主在通信等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在通信领域笔记&#xf…

Python+Requests+PyTest+Excel+Allure 接口自动化测试实战

目录 本文主要介绍了PythonRequessPyTestExcelAllure 接口自动化测试实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 Unittest是Python标准库中自带的单元测试…

nginx 模块相关配置及结构理解

文章目录 模块配置结构模块配置指令先看一下 ngx_command_t 结构一个模块配置的demo简单模块配置的案例演示 模块上下文结构模块的定义 模块配置结构 Nginx中每个模块都会提供一些指令,以便于用户通过配置去控制该模块的行为。 Nginx的配置信息分成了几个作用域(sc…

【Vue】核心特性(响应式)

响应式&#xff1a; 数据变化&#xff0c;视图自动更新 接下来使用一个例子来体现一下什么是响应式 案例一&#xff1a; 访问数据&#xff0c;视图自动更新 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><…

【C/PTA】函数专项练习(四)

本文结合PTA专项练习带领读者掌握函数&#xff0c;刷题为主注释为辅&#xff0c;在代码中理解思路&#xff0c;其它不做过多叙述。 目录 6-1 计算A[n]1/(1 A[n-1])6-2 递归实现顺序输出整数6-3 自然数的位数(递归版)6-4 分治法求解金块问题6-5 汉诺塔6-6 重复显示字符(递归版)…

【git】使用ssh

前言 git之前一直使用https&#xff0c;因为很方便随时随地都可以用。最近吧代码托管到GitHub&#xff0c;使用https就使用不了。后面听同事说GitHub使用ssh是没问题的&#xff0c;就想着尝试一下。 git ssh配置 设置用户名和邮箱 git config --global use.name usernamegit…

性能测试的指南:测试类型、性能测试步骤、最佳实践等!

近期公司为了节省成本搞了一波机房迁移&#xff0c;整合了一些南美部署架构。有一些上google云和有些下阿里云等大的调整。 在做机房迁移项目当中就需要思考如何进行性能测试&#xff0c;这种大的机房迁移SRE&#xff08;运维&#xff09;会针对组件会做一些单组件的性能测试&a…

【LeetCode刷题-回溯】-- 47.全排列II

47.全排列II 主要需要解决全排列不重复的问题&#xff0c;设定一个规则&#xff0c;保证在填第i个数的时候重复数字只会被填入一次即可&#xff0c;而在本题中&#xff0c;我们选择对原数组排序&#xff0c;保证相同的数字都相邻&#xff0c;然后每次填入的数一定是这个数所在重…

基于深度学习的文本分类

通过构建更复杂的深度学习模型可以提高分类的准确性&#xff0c;即分别基于TextCNN、TextRNN和TextRCNN三种算法实现中文文本分类。 项目地址&#xff1a;zz-zik/NLP-Application-and-Practice: 本项目将《自然语言处理与应用实战》原书中代码进行了实现&#xff0c;并在此基础…