当前位置: 首页 > news >正文

Spring实战 | Spring AOP核心功能分析之葵花宝典

国庆中秋特辑系列文章:

国庆中秋特辑(八)Spring Boot项目如何使用JPA

国庆中秋特辑(七)Java软件工程师常见20道编程面试题

国庆中秋特辑(六)大学生常见30道宝藏编程面试题

国庆中秋特辑(五)MySQL如何性能调优?下篇

国庆中秋特辑(四)MySQL如何性能调优?上篇

国庆中秋特辑(三)使用生成对抗网络(GAN)生成具有节日氛围的画作,深度学习框架 TensorFlow 和 Keras 来实现

国庆中秋特辑(二)浪漫祝福方式 使用生成对抗网络(GAN)生成具有节日氛围的画作

国庆中秋特辑(一)浪漫祝福方式 用循环神经网络(RNN)或长短时记忆网络(LSTM)生成祝福诗词

目录

  • 一、Spring AOP 简介
  • 二、Spring AOP 原理
  • 三、Spring AOP 案例分析
  • 四、Spring AOP 提供了两种动态代理方式

Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的一个重要模块。
在这里插入图片描述

一、Spring AOP 简介

Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的一个重要模块,用于提供声明式的事务管理、日志记录、性能监控等功能。Spring AOP 底层依赖于 AspectJ 实现,可以与 Spring 框架无缝集成,提供一种更加简单、直观的方式来处理企业应用中的常见问题。

二、Spring AOP 原理

  1. 代理机制
    Spring AOP 采用代理机制实现,可以分为 JDK 动态代理和 CGLIB 动态代理。JDK 动态代理是通过实现目标类的接口,生成目标类的代理对象;CGLIB 动态代理是通过继承目标类,生成目标类的子类作为代理对象。
  2. 通知(Advice)
    通知是 Spring AOP 中实现切面功能的核心,可以分为五种类型:Before、After、AfterReturning、AfterThrowing 和 Around。通知的作用是在目标方法执行前、后或者抛出异常时执行特定的逻辑,实现对目标方法的增强。
  3. 切入点(Pointcut)
    切入点是 Spring AOP 中定义的一个表达式,用于指定哪些方法需要被增强。切点表达式可以使用 AspectJ 语言来编写,非常灵活。通过定义切入点,可以精确地控制哪些方法需要被增强。
  4. 切面(Aspect)
    切面是 Spring AOP 中的一种组件,包含切点和通知。切面可以将通用的逻辑(如日志、事务管理等)封装在一起,便于管理和维护。在 Spring AOP 中,可以通过 XML 配置文件或者 Java 代码来定义切面。
  5. 自动代理
    Spring AOP 框架支持自动代理,可以在运行时自动为指定类生成代理对象。自动代理的核心是 Spring AOP 容器,负责管理代理对象、切面和通知。通过自动代理,可以简化开发者的操作,提高开发效率。

三、Spring AOP 案例分析

以下通过一个简单的案例来演示 Spring AOP 的使用。

  1. 配置文件
    首先,创建一个配置文件 applicationContext.xml,用于定义目标类和切面类。
<beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:aop="http://www.springframework.org/schema/aop"  xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd  http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 定义目标类 -->  <bean id="target" class="com.example.TargetClass"></bean><!-- 定义切面类 -->  <bean id="aspect" class="com.example.AspectClass"></bean><!-- 开启自动代理 -->  <aop:config proxy-target-class="true">  <!-- 指定切入点表达式 -->  <aop:aspect ref="aspect">  <aop:before pointcut="execution(* com.example.TargetClass.*(..))" method="com.example.AspectClass.beforeAdvice"></aop:before>  <aop:after pointcut="execution(* com.example.TargetClass.*(..))" method="com.example.AspectClass.afterAdvice"></aop:after>  </aop:aspect>  </aop:config>  
</beans>  
  1. 目标类(TargetClass)
    目标类是一个简单的计算类,包含两个方法:doAdd 和 doSubtract。
package com.example;
public class TargetClass {  public int doAdd(int a, int b) {  System.out.println("TargetClass doAdd method called");  return a + b;  }public int doSubtract(int a, int b) {  System.out.println("TargetClass doSubtract method called");  return a - b;  }  
}
  1. 切面类(AspectClass)
    切面类包含两个通知方法:beforeAdvice 和 afterAdvice,分别用于在目标方法执行前和执行后执行特定逻辑。
package com.example;
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.After;
public class AspectClass {  @Before("execution(* com.example.TargetClass.*(..))")  public void beforeAdvice(JoinPoint joinPoint) {  System.out.println("Before advice: " + joinPoint.getSignature().getName());  }@After("execution(* com.example.TargetClass.*(..))")  public void afterAdvice(JoinPoint joinPoint) {  System.out.println("After advice: " + joinPoint.getSignature().getName());  }  
}
  1. 测试类(TestClass)
    测试类用于测试 Spring AOP 的效果。
package com.example;
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestClass {  public static void main(String[] args) {  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  TargetClass target = (TargetClass) context.getBean("target");int result1 = target.doAdd(2, 3);  int result2 = target.doSubtract(5, 2);System.out.println("Result 1: " + result1);  System.out.println("Result 2: " + result2);  }  
}

运行测试类,输出结果如下:

TargetClass doAdd method called  
Before advice: doAdd  
After advice: doAdd  
Result 1: 5  
TargetClass doSubtract method called  
Before advice: doSubtract  
After advice: doSubtract  
Result 2: 3  

从输出结果可以看出,在目标方法执行前和执行后分别执行了 beforeAdvice 和 afterAdvice 方法,说明 Spring AOP 已经成功实现了对目标方法的增强。

四、Spring AOP 提供了两种动态代理方式

JDK 动态代理和 CGLIB 动态代理。JDK 动态代理是基于接口实现的,而 CGLIB 动态代理是基于类实现的。这两种代理方式在性能上有一定的差别,JDK 动态代理更适合用于接口较多的场景,而 CGLIB 动态代理则更适合用于类较多的场景。
4.1 下面是一个简单的 Spring AOP JDK 动态代理示例,演示了如何使用 Spring AOP 实现日志切面:

  1. 首先,创建一个切面类(Aspect),包含一个通知(Advice):
package com.example.aspect;
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.annotation.AfterReturning;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.Pointcut;  
import org.springframework.stereotype.Component;
@Aspect  
@Component  
public class LoggingAspect {@Pointcut("execution(* com.example.service.*.*(..))")  public void serviceMethods() {  }@Before("serviceMethods()")  public void logBefore(JoinPoint joinPoint) {  System.out.println("Before method: " + joinPoint.getSignature().getName());  }@AfterReturning(pointcut = "serviceMethods()", returning = "result")  public void logAfterReturning(JoinPoint joinPoint, Object result) {  System.out.println("After returning method: " + joinPoint.getSignature().getName());  System.out.println("Result: " + result);  }  
}
  1. 接下来,创建一个目标类(Target Class),包含一个需要增强的方法:
package com.example.service;
import org.springframework.stereotype.Service;
@Service  
public class TargetService {public String sayHello(String name) {  System.out.println("Hello, " + name);  return "Hello, " + name;  }  
}
  1. 然后,创建一个 Spring 配置类,启用 AOP 支持,并扫描包含切面和目标类的包:
package com.example;
import org.springframework.context.annotation.ComponentScan;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration  
@EnableAspectJAutoProxy  
@ComponentScan(basePackages = {"com.example.aspect", "com.example.service"})  
public class AppConfig {  
}
  1. 最后,创建一个测试类,使用 Spring AOP 提供的 API 调用目标类的方法:
package com.example;
import org.springframework.context.ApplicationContext;  
import org.springframework.context.annotation.AnnotationConfigApplicationContext;  
import org.springframework.stereotype.Component;
@Component  
public class Test {public static void main(String[] args) {  ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  TargetService targetService = context.getBean(TargetService.class);  String result = targetService.sayHello("World");  System.out.println("Result: " + result);  }  
}

运行测试类,你将看到目标方法被切面增强的日志输出。这个示例展示了如何使用 Spring AOP JDK 动态代理实现简单的日志切面,以记录目标方法执行的前后状态。这有助于实现代码的重用和提高可维护性。

4.2 下面是一个简单的 Spring AOP CGLIB 动态代理示例,演示了如何使用 Spring AOP 实现日志切面:

  1. 首先,创建一个切面类(Aspect),包含一个通知(Advice):
package com.example.aspect;
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.annotation.AfterReturning;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Pointcut;  
import org.springframework.stereotype.Component;
@Aspect  
@Component  
public class LoggingAspect {@Pointcut("execution(* com.example.service.*.*(..))")  public void serviceMethods() {  }@Before("serviceMethods()")  public void logBefore(JoinPoint joinPoint) {  System.out.println("Before method: " + joinPoint.getSignature().getName());  }@AfterReturning(pointcut = "serviceMethods()", returning = "result")  public void logAfterReturning(JoinPoint joinPoint, Object result) {  System.out.println("After returning method: " + joinPoint.getSignature().getName());  System.out.println("Result: " + result);  }  
}
  1. 接下来,创建一个目标类(Target Class),包含一个需要增强的方法:
package com.example.service;
import org.springframework.stereotype.Service;
@Service  
public class TargetService {public String sayHello(String name) {  System.out.println("Hello, " + name);  return "Hello, " + name;  }  
}
  1. 然后,创建一个 Spring 配置类,启用 AOP 支持,并扫描包含切面和目标类的包:
package com.example;
import org.springframework.context.annotation.ComponentScan;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration  
@EnableAspectJAutoProxy  
@ComponentScan(basePackages = {"com.example.aspect", "com.example.service"})  
public class AppConfig {  
}
  1. 最后,创建一个测试类,使用 Spring AOP 提供的 API 调用目标类的方法:
package com.example;
import org.springframework.context.ApplicationContext;  
import org.springframework.context.annotation.AnnotationConfigApplicationContext;  
import org.springframework.stereotype.Component;
@Component  
public class Test {public static void main(String[] args) {  ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  TargetService targetService = context.getBean(TargetService.class);  String result = targetService.sayHello("World");  System.out.println("Result: " + result);  }  
}

运行测试类,你将看到目标方法被切面增强的日志输出。这有助于实现代码的重用和提高可维护性。
需要注意的是,CGLIB 动态代理需要 TargetService 类实现 equals() 和 hashCode() 方法,否则会报错。这是因为 CGLIB 需要生成目标类的代理类,而如果 TargetService 类没有实现 equals() 和 hashCode() 方法,那么生成的代理类将无法正确处理目标类的对象。

相关文章:

Spring实战 | Spring AOP核心功能分析之葵花宝典

国庆中秋特辑系列文章&#xff1a; 国庆中秋特辑&#xff08;八&#xff09;Spring Boot项目如何使用JPA 国庆中秋特辑&#xff08;七&#xff09;Java软件工程师常见20道编程面试题 国庆中秋特辑&#xff08;六&#xff09;大学生常见30道宝藏编程面试题 国庆中秋特辑&…...

linux之/etc/skel目录

/etc/skel目录是在使用useradd添加用户时&#xff0c;一个需要用到的目录&#xff0c;该目录用来存放新建用户时需要拷贝到新建用户家目录下的文件。即&#xff1a;当我们新建新用户时&#xff0c;这个目录下的所有文件会自动被复制到新建用户的家目录下&#xff0c;默认情况下…...

文件介绍---C语言编程

0 Preface/Foreword 1 C文件概述 文件&#xff08;File&#xff09;是程序设计中的一个重要的概念。所谓“文件”一般指存储在外部介质上数据的集合。一批数据是以文件的形式存放在外部介质&#xff08;如磁盘&#xff09;上。操作系统是以文件为单位对数据进行管理&#xff0c…...

软考 系统架构设计师系列知识点之特定领域软件体系结构DSSA(6)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之特定领域软件体系结构DSSA&#xff08;5&#xff09; 所属章节&#xff1a; 第7章. 系统架构设计基础知识 第5节. 特定领域软件体系结构 相关试题 3. 特定领域软件架构&#xff08;Domain Specific Software Archite…...

TensorFlow入门(二十三、退化学习率)

学习率 学习率,控制着模型的学习进度。模型训练过程中,如果学习率的值设置得比较大,训练速度会提升,但训练结果的精度不够,损失值容易爆炸;如果学习率的值设置得比较小,精度得到了提升,但训练过程会耗费太多的时间,收敛速度慢,同时也容易出现过拟合的情况。 退化学习率 退化学…...

登录中获取验证码的节流

一. 验证码框 <el-input placeholder"请输入验证码" prefix-icon"el-icon-lock" v-model"ruleForm.code"><el-button slot"suffix" :disabled"disabled" type"text" size"mini" click"ch…...

spring boot 实现Minio分片上传

应用场景 分片上传&#xff0c;就是将所要上传的文件&#xff0c;按照一定的大小&#xff0c;将整个文件分隔成多个数据块&#xff08;我们称之为Part&#xff09;来进行分别上传&#xff0c;上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。 分片上传的场景…...

2023年09月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C编程&#xff08;1~8级&#xff09;全部真题・点这里 Python编程&#xff08;1~6级&#xff09;全部真题・点这里 第1题&#xff1a;生日相同 在一个有180人的大班级中&#xff0c;存在两个人生日相同的概率非常大&#xff0c;现给出每个学生的名字&#xff0c;出生月日。试…...

docker-compose 部署示例

文章目录 docker-compose文件格式docker-compose 下载 docker-compose文件格式 这个软件的实际很小&#xff0c;只是根据配置文件产生一些docker命令来执行可以。 配置文件本身是yml的格式&#xff0c;如下 version: 3.5services:# Etherpad: real-time collaborative docume…...

新版WordPress插件短视频去水印小程序源码

最新版去水印小程序源码&#xff0c;本版本全开源&#xff0c;是WordPress插件 上传到Wordpress 安装插件 启动之后 绑定自己的小程序id wordpress可以在宝塔一键部署 也可以用我的这个 搭建前我们需要一下东西&#xff1a; 第一个&#xff1a;一台服务器&#xff08;国内外都可…...

如何提高MES系统的落地成功率?

导 读 ( 文/ 2768 ) 制造执行系统&#xff08;MES&#xff09;在现代制造业中扮演着至关重要的角色&#xff0c;但实施MES系统并取得成功并非易事。为了帮助企业提高MES系统的落地成功率&#xff0c;本文将介绍关键的方法和策略。通过深入了解业务需求、有效的团队合作、全面的…...

private key ssh连接服务器

这里用到的软件是PuTTY。 https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 保存本地rsa文件后&#xff0c;打开软件PuTTYgen&#xff0c;点击Load导入文件&#xff0c;输入Key passphrase即密码&#xff0c;保存至本地。 随后在PuTTY配置ssh的用户名 来Cred…...

PDF-Word-图片等的互相转换

轻闪PDF客户端 - 功能强大的一站式PDF工具 | PDF编辑、转换、阅读 上面页面支持PDF转换成各类别&#xff1a;鼠标停留在PDF工具&#xff0c;点击转换类型即可在线转换 Word-PDF&#xff1a;word文档打开word文件中&#xff0c;点击文件->另存为->另存为的位置->保存…...

【VR开发】【Unity】0-课程简介和概述

【说明】 这是我录制的一套VR基础开发课程的文字版本&#xff0c;更加便于快速参考。 应大家在后台所提的需求&#xff0c;从今天开始&#xff0c;我计划带给大家一套完整达40课时的VR开发基础课程。 在开始学习前需要注意如下几点&#xff1a; 本教程基于Unity2022.2.1f1版…...

Java面试题-Java核心基础-第三天(基本数据类型)

目录 一、Java的基本数据类型了解吗&#xff1f; 二、基本类型和包装类型的区别 三、包装类型的缓存机制了解吗&#xff1f; 四、自动拆箱和自动装箱了解吗&#xff1f; 五、为什么浮点数在运算的时候会有精度损失的风险&#xff1f; 六、如何解决浮点数在运算时存在的精度…...

Bean容器里的单例是根据什么识别它是同一个类呢?(比如容器里创建了A类,再去用这个A类的时候,Bean容器怎么知道这个就是A类?)

Spring容器中的Bean的识别主要依赖于Bean的名称&#xff08;ID&#xff09;和类型。以下是详细解释&#xff1a; Bean的名称&#xff08;ID&#xff09;&#xff1a;每个Bean在Spring容器中都必须有一个唯一的名称&#xff08;ID&#xff09;。这个名称通常在配置文件中、Java…...

简述 happens - before 八大规则

“Happens-Before” 是Java内存模型中的概念&#xff0c;用于描述多线程程序中操作之间的顺序和可见性关系。它定义了一组规则&#xff0c;哪些操作具有可预测的行为。以下是"Happens-Before" 的八大规则&#xff1a; 程序顺序规则&#xff08;Program Order Rule&am…...

windows flask 多进程高并发

最近在做的一个项目&#xff0c;需要将十几个python函数封装程flask服务供外界调用&#xff0c;每个函数之间没有什么关系&#xff0c;相互独立。虽然感觉不是很难&#xff0c;但因为用的windows系统&#xff0c;遇到的坑比较多&#xff0c;在此一一总结一下。 flask偶尔出现卡…...

【设计模式】十、组合模式

文章目录 案例组合模式基本介绍类图代码 组合模式在 JDK 集合的源码分析组合模式的注意事项和细节 案例 编写程序展示一个学校院系结构&#xff1a;需求是这样&#xff0c;要在一个页面中展示出学校的院系组成&#xff0c;一个学校有多个学院&#xff0c;一个学院有多个系。如…...

React知识点系列(8)-每天10个小知识

目录 1. 在 React 中&#xff0c;什么是受控组件和非受控组件&#xff1f;请解释一下它们之间的区别和适用场景。2. 如何使用 React 的 useReducer Hook 来管理组件状态&#xff1f;请描述一下 useReducer 的工作原理和适用场景。工作原理&#xff1a;适用场景&#xff1a; 3. …...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...