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() 方法,那么生成的代理类将无法正确处理目标类的对象。

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

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

相关文章

计算机毕业设计选什么题目好?springboot 试题库管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

学信息系统项目管理师第4版系列26_项目绩效域(下)

1. 项目工作绩效域 1.1. 涉及项目工作相关的活动和职能 1.2. 预期目标 1.2.1. 高效且有效的项目绩效 1.2.2. 适合项目和环境的项目过程 1.2.3. 干系人适当的沟通和参与 1.2.4. 对实物资源进行了有效管理 1.2.5. 对采购进行了有效管理 1.2.6. 有效处理了变更 1.2.7. 通…

css3 table表格

使用CSS3来美化HTML表格&#xff08;table&#xff09;可以提高表格的外观和可读性 表格样式&#xff1a; table { width: 100%; border-collapse: collapse; } width: 100%; 使表格宽度充满其容器。border-collapse: collapse; 合并相邻的表格边框&#xff0c;使表格看起来更整…

互联网Java工程师面试题·Java 并发编程篇·第五弹

目录 52、什么是线程池&#xff1f; 为什么要使用它&#xff1f; 53、怎么检测一个线程是否拥有锁&#xff1f; 54、你如何在 Java 中获取线程堆栈&#xff1f; 55、JVM 中哪个参数是用来控制线程的栈堆栈小的? 56、Thread 类中的 yield 方法有什么作用&#xff1f; 57、…

Chrome插件精选 — 暗色主题插件

Chrome实现同一功能的插件往往有多款产品&#xff0c;逐一去安装试用耗时又费力&#xff0c;在此为某一类型插件记录下比较好用的一款或几款&#xff0c;便于节省尝试的时间和精力。 Dark Reader 下载地址 (访问密码: 8276) Dark Reader是一款浏览器扩展程序&#xff0c;用于…

C语言达到什么水平才能从事单片机工作

C语言达到什么水平才能从事单片机工作 从事单片机工作需要具备一定的C语言编程水平。以下是几个关键要点&#xff1a;基本C语言知识&#xff1a; 掌握C语言的基本语法、数据类型、运算符、流控制语句和函数等基本概念。最近很多小伙伴找我&#xff0c;说想要一些C语言学习资料&…

晨控CK-GW06系列网关与汇川可编程控制器MOSBUSTCP通讯手册

晨控CK-GW06系列网关与汇川可编程控制器MOSBUSTCP通讯手册 晨控CK-GW06系列是支持标准工业通讯协议 MODBUSTCP 的网关控制器,方便用户集成到PLC等控制系统中。本控制器提供了网络 POE 供电和直流电源供电两种方式&#xff0c;确保用户在使用无 POE 供电功能的交换机时可采用外…

Android 12.0 hal层添加自定义hal模块功能实现

1. 前言 在12.0的系统rom定制化开发中,在 对hal模块进行开发时,需要通过添加自定义的hal模块来实现某些功能时,就需要添加hal模块的相关功能,接下来就来实现一个案例来供参考 接下来就来具体实现这个功能 2.hal层添加自定义hal模块功能实现的核心类 hardware\interfaces…

用wpf替代winform 解决PLC数据量过大页面卡顿的问题

winform 由于不是数据驱动, 页面想刷新数据必须刷新控件, wpf则不用. 可以利用wpf 的数据绑定和IOC, 页面中的消息传递, itemscontrol 实现大量数据刷新, 上位机页面不卡顿 跨页面传值, 可以用两种方法: Toolkit.Mvvm中的Message和IOC. 下面是代码: using Microsoft.Extensio…

3.2.5:VBA对单元格操作的引申

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…

天堂2服务器安装教程

我们在架设游戏的时候很多时候都是摸不着头脑不知道从何下手&#xff0c;只要我们理清思路一步一步的操作步骤是不难的&#xff0c;其中的细节注意到就能成功的架设起来。下面跟大家来说说从哪下手。 首先我们需要有自己的服务器&#xff0c;系统我们就用Windows 2008 Server。…

解锁机器学习-梯度下降:从技术到实战的全面指南

目录 一、简介什么是梯度下降&#xff1f;为什么梯度下降重要&#xff1f; 二、梯度下降的数学原理代价函数&#xff08;Cost Function&#xff09;梯度&#xff08;Gradient&#xff09;更新规则代码示例&#xff1a;基础的梯度下降更新规则 三、批量梯度下降&#xff08;Batc…

MySQL创建数据库、创建表操作和用户权限

1、创建数据库school&#xff0c;字符集为utf8 2、在school数据库中创建Student和Score表 3、授权用户tom&#xff0c;密码Mysql123&#xff0c;能够从任何地方登录并管理数据库school 4、使用mysql客户端登录服务器&#xff0c;重置root密码

JavaScript之正则表达式

详见MDN 正则表达式(RegExp) 正则表达式不是JS独有的内容&#xff0c;大部分语言都支持正则表达式 JS中正则表达式使用得不是那么多&#xff0c;我们可以尽量避免使用正则表达式 在JS中&#xff0c;正则表达式就是RegExp对象&#xff0c;RegExp 对象用于将文本与一个模式匹配 正…

【问题解决】【爬虫】抓包工具charles与pycharm发送https请求冲突问题

问题&#xff1a; 开启charles抓包&#xff0c;运行pycharm发送https请求报以下错误 解决&#xff1a; 修改python代码&#xff0c;发送请求时添加verify false&#xff0c;此时charles也能抓取到pycharm发送的请求 2. 关闭charles抓包&#xff0c;取消勾选window proxy

windows安装nvm以及解决yarn问题

源代码 下载 下一步一下步安装即可 检查是否安装成功 nvm出现上面的代码即可安装成功 常用命令 查看目前安装的node版本 nvm list [available]说明没有安装任何版本&#xff0c;下面进行安装 nvm install 18.14使用该版本 node use 18.14.2打开一个新的cmd输入node -…

Apache Lucene 7.0 - 索引文件格式

Apache Lucene 7.0 - 索引文件格式 文章目录 Apache Lucene 7.0 - 索引文件格式介绍定义反向索引字段类型段文档数量索引结构概述文件命名文件扩展名摘要锁文件 原文地址 介绍 这个文档定义了在这个版本的Lucene中使用的索引文件格式。如果您使用的是不同版本的Lucene&#xf…

vue面试题-应用层

MVC与MVVM MVCMVVM 双向数据绑定 vue2 双向绑定原理 v-model原理 vue3 双向绑定原理 示例 对比 vue2响应式原理和Vue3响应式原理 data为什么是函数?v-if 与 v-show MVC与MVVM MVC和MVVM是两种流行的设计模式&#xff0c;它们都是用于构建动态应用程序的框架。 MVC MVC&#…

【重拾C语言】十一、外部数据组织——文件

目录 前言 十一、外部数据组织——文件 11.1 重新考虑户籍管理问题——文件 11.2 文件概述 11.2.1 文件分类 11.2.2 文件指针、标记及文件操作 11.3 打开、关闭文件 11.4 I/O操作 11.4.1 字符读写 11.4.2 字符串读写 11.4.3 格式化读写 11.4.4 数据块读写 11.4.5 …

【神经网络】如何在Pytorch中从零开始将MNIST网络量化为8位

论文&#xff1a; Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference 下载地址&#xff1a;https://arxiv.org/pdf/1712.05877.pdf 更新:量化感知训练的博客文章是在线的&#xff0c;并在这里链接&#xff0c;通过它我们可以训…