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

Spring 学习(二)AOP

一、什么是AOP

Aspect Oriented Programming,即面向切面编程。对一个大型项目的代码而言,整个系统要求关注安全检查、日志、事务等功能,这些功能实际上“横跨”多个业务方法。在一般的OOP编程里,需要在每一个业务方法内添加相关非业务方法的调用,这实际上是冗余的。如果能够类似IoC一样,这样的安全检查,日志,事务功能单独提取放到外面,核心业务方法不需要关注,就能降低代码耦合度。如果我们以AOP的视角来编写上述业务,可以依次实现:

  • 核心逻辑Service
  • 切面逻辑,即:
    • 权限检查的Aspect;
    • 日志的Aspect;
    • 事务的Aspect。
      然后,以某种方式,让框架来把上述3个Aspect以Proxy的方式“织入”到Service中,这样一来,就不必编写复杂而冗长的Proxy模式

AOP对于解决特定问题,例如事务管理非常有用,这是因为分散在各处的事务代码几乎是完全相同的,并且它们需要的参数(JDBC的Connection)也是固定的。另一些特定问题,如日志,就不那么容易实现,因为日志虽然简单,但打印日志的时候,经常需要捕获局部变量,如果使用AOP实现日志,我们只能输出固定格式的日志,因此,使用AOP时,必须适合特定的场景。


二、AOP

常见的AOP术语包括:

  • 切面(Aspect):横跨多个类和方法的模块,定义了一组横切关注点的行为。
  • 连接点(Join Point):程序执行过程中可以插入切面的特定点,例如方法调用、异常抛出等。
  • 通知(Advice):切面在连接点上执行的行为,包括前置通知、后置通知、环绕通知、异常通知和最终通知等。
  • 切点(Pointcut):定义了一组连接点的表达式,用于确定切面在哪些连接点上执行。
  • 引入(Introduction):允许向现有类添加新的方法或属性。
  • 织入(Weaving):将切面应用到目标对象中,以创建新的代理对象或修改现有对象的字节码。

例如,编写日志loggin切片

@Aspect
@Component
public class LoggingAspect {// 在执行UserService的每个方法前执行:@Before("execution(public * com.itranswarp.learnjava.service.UserService.*(..))")public void doAccessCheck() {System.err.println("[Before] do access check...");}// 在执行MailService的每个方法前后执行:@Around("execution(public * com.itranswarp.learnjava.service.MailService.*(..))")public Object doLogging(ProceedingJoinPoint pjp) throws Throwable {System.err.println("[Around] start " + pjp.getSignature());Object retVal = pjp.proceed();System.err.println("[Around] done " + pjp.getSignature());return retVal;}
}
  • @Before()里面的字符串是告诉AspectJ应该在何处执行该方法,这里写的意思是:执行UserService的每个public方法前执行doAccessCheck()代码
  • @Around注解,它和@Before不同,@Around可以决定是否执行目标方法
  • @Aspect注解,表示它的@Before标注的方法需要注入到UserService的每个public方法执行前,@Around标注的方法需要注入到MailService的每个public方法执行前后

我们需要给@Configuration类加上一个@EnableAspectJAutoProxy注解,Spring的IoC容器看到这个注解,就会自动查找带有@Aspect的Bean,然后根据每个方法的@Before、@Around等注解把AOP注入到特定的Bean中。

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class AppConfig {...
}

三、AOP实现原理

AOP原理实际上就是一个代理类的实现,这个代理是借由Spring容器实现的,例如,将LoggingAspect.doAccessCheck注入UserService的每个public方法中,可以通过如下实现:

public UserServiceAopProxy extends UserService {private UserService target;private LoggingAspect aspect;public UserServiceAopProxy(UserService target, LoggingAspect aspect) {this.target = target;this.aspect = aspect;}public User login(String email, String password) {// 先执行Aspect的代码:aspect.doAccessCheck();// 再执行UserService的逻辑:return target.login(email, password);}public User register(String email, String password, String name) {aspect.doAccessCheck();return target.register(email, password, name);}...
}

容器自动为我们创建了注入了Aspect的子类,取代原始的UserService,并把被@Before @Around关键词修饰的方法覆写。


四、拦截器

AOP拦截器通常是指用于拦截和处理方法调用的组件或类。这些拦截器可以在方法调用前、后或异常抛出时执行特定的逻辑

  • @Before:该注解用于定义前置拦截器。在目标方法执行前,被注解的方法将被执行。可以用于实现预处理、参数验证和权限检查等功能。
  • @AfterReturning:该注解用于定义后置拦截器。在目标方法成功执行并返回结果后,被注解的方法将被执行。可以用于实现日志记录、结果处理和清理操作等功能。
  • @Around:该注解用于定义环绕拦截器。在目标方法执行前后,被注解的方法将被执行。通过在拦截器方法中调用ProceedingJoinPoint.proceed()来控制目标方法的执行,并可以在适当的时机添加额外的逻辑。
  • @AfterThrowing:
    该注解用于定义异常拦截器。在目标方法抛出异常时,被注解的方法将被执行。可以用于实现异常处理、错误日志记录等功能。

通过使用这些注解,可以将拦截器逻辑与特定的切点(Pointcut)相结合,实现对核心业务逻辑的拦截和处理。可以使用execution()表达式来定义切点,指定要拦截的方法的执行。这些注解可以与Spring AOP的其他功能和配置一起使用,如切面(Aspect)、通知(Advice)和配置文件等,以实现更复杂的AOP编程。


五、注解装配

使用注解装配AOP时,最好需要在被装配的Bean处使用注解标记,被装配的Bean最好自己能清清楚楚地知道自己被安排了。例如,Spring提供的@Transactional。

我们以一个实际例子演示如何使用注解实现AOP装配。为了监控应用程序的性能,我们定义一个性能监控的注解:

@Target(METHOD)
@Retention(RUNTIME)
public @interface MetricTime {String value();
}/**************************************/
@Component
public class UserService {// 监控register()方法性能:@MetricTime("register")public User register(String email, String password, String name) {...}...
}/**************************************/
@Aspect
@Component
public class MetricAspect {@Around("@annotation(metricTime)")public Object metric(ProceedingJoinPoint joinPoint, MetricTime metricTime) throws Throwable {String name = metricTime.value();long start = System.currentTimeMillis();try {return joinPoint.proceed();} finally {long t = System.currentTimeMillis() - start;// 写入日志或发送至JMX:System.err.println("[Metrics] " + name + ": " + t + "ms");}}
}

这段代码中,一直对@Around("@annotation(metricTime)")存在疑惑,为什么不是MetricTime(类)而是metricTime(参数名),关键在@annotation。

@annotation 是 Spring AOP 中的一个切点指示器,用于匹配被任意注解标记的方法或类。在切点表达式中使用 @annotation(annotationType),其中 annotationType 是要匹配的注解类型,可以是任何有效的注解类型。这个切点指示器的作用是,在切面中匹配被特定注解标记的方法或类,以便在相应的切面方法中对它们进行处理。

以下实例中,@Around(“@annotation(com.example.MyAnnotation)”) 表达式表示匹配被 @MyAnnotation 注解标记的方法。当调用这些被标记的方法时,切面中的 myAdvice 方法会被触发

@Aspect
@Component
public class MyAspect {// 匹配被 @MyAnnotation 标记的方法@Around("@annotation(com.example.MyAnnotation)")public Object myAdvice(ProceedingJoinPoint joinPoint) throws Throwable {// 在方法执行前后执行自定义逻辑// ...return joinPoint.proceed();}}

但在@Around("@annotation(metricTime)")中,由于切面方法metric要用到被标记注解的实例,而不只是匹配注解类型。那么在 @annotation() 中需要传入该注解的实例。具体来说,如果被切入的方法的参数列表中有一个具有某个特定注解的参数,则可以在切面表达式中使用 @annotation(parameterName) 来匹配并获取该注解的实例。

相关文章:

Spring 学习(二)AOP

一、什么是AOP Aspect Oriented Programming,即面向切面编程。对一个大型项目的代码而言,整个系统要求关注安全检查、日志、事务等功能,这些功能实际上“横跨”多个业务方法。在一般的OOP编程里,需要在每一个业务方法内添加相关非…...

笔记1.1 计算机网络基本概念

计算机网络是通信技术与计算机技术紧密结合的产物 通信系统模型: 计算机网络是一种通信网络 计算机网络是互连的、自洽的计算机集合。 互连:互联互通 自洽:无主从关系 通过交换网络互连主机 Internet:数以百万计的互连的计算设…...

液压切管机配套用液压泵站比例阀放大器

液压切管机配套用液压泵站是液压系统的动力源,可按机械设备工况需要提供一定压力、流量和清洁度的工作介质。它由泵组、油箱组件、控温组件、滤油器组件及蓄能器组件等组合而成,液压泵站主要服务于大型管道工程。...

C++ Primer Plus 第七章笔记

目录 函数基本知识 没有返回值的函数:void函数 有返回值的函数: 函数原型 1.为什么需要函数原型? 2.函数原型的语法 3.函数原型的功能 按值传递函数参数 形参和实参 局部变量 参数问题 使用const指针参数 调用自身的函数&#xf…...

常用数据库的 API - 开篇

API API 这个词在大多数人看来可能和 CNS 差不多,前者天天听说就是用不上,后者天天读就是发不了。 不过,通过今天的一个简短介绍,今后 API 这个东西你就用上了,因为在文章最后我将会展示一个最最基础且高频的 API 使…...

C++之生成详细汇编代码(二百一十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...

AIGC|当一个程序员学会用AI来辅助编程实践

一、辅助编程 作为主要以 JAVA 语言为核心的后端开发者,其实,早些时间我也用过比如 Codota、Tabnine、Github 的 Copilot、阿里的 AI Coding Assistant 等 IDEA 插件,但是我并没有觉得很惊奇,感觉就是生成一些代码片段罢了&#x…...

9.14号作业

仿照vector手动实现自己的myVector&#xff0c;最主要实现二倍扩容功能 有些功能&#xff0c;不会 #include <iostream>using namespace std; //创建vector类 class Vector { private:int *data;int size;int capacity; public://无参构造Vector(){}//拷贝构造Vector(c…...

【面试题】C/C++ 中指针和引用的区别

指针是一个独立的对象&#xff0c;它可以指向不同的变量或对象&#xff0c;可以重新赋值给其他变量。而引用是已存在的变量的别名&#xff0c;它必须在定义时初始化&#xff0c;并且不能重新绑定到另一个变量。指针可以是空指针&#xff08;nullptr&#xff09;&#xff0c;它不…...

spring boot 整合多数据源

多数据源产生的场景 一般情况下&#xff0c;不会有多数据源这样的场景出现&#xff0c;但老项目或者特殊需求的项目&#xff0c;可能会有这样的场景 同一个应用需要访问两个数据库不用数据库中间件的读写分离 注入数据源选择的时机 声明两个数据源实例&#xff0c;在getConnect…...

数据集成:数据挖掘的准备工作之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…...

xml配置文件密码特殊字符处理

错误姿势&#xff1a; 正确姿势&#xff1a;采取转义符的方式 常用转义符&#xff1a;...

遥感数据与作物模型同化

基于过程的作物生长模拟模型DSSAT是现代农业系统研究的有力工具&#xff0c;可以定量描述作物生长发育和产量形成过程及其与气候因子、土壤环境、品种类型和技术措施之间的关系&#xff0c;为不同条件下作物生长发育及产量预测、栽培管理、环境评价以及未来气候变化评估等提供了…...

UI库DHTMLX Suite v8.2发布全新表单组件,让Web表单实现高度可定制!

DHTMLX Suite v8.2日前已正式发布&#xff0c;此版本的核心是DHTMLX Form&#xff0c;这个小部件接收了4个备受期待的新控件&#xff0c;如Fieldset、Avatar、Toggle和ToggleGroup。官方技术团队还为Grid和TreeGrid小部件中的页眉/页脚工具提示提供了一系列新的配置选项等。 在…...

河北省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著

河北省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著...

什么是卷积002

文章目录 前言1.卷积网络和传统网络区别2.卷积神经网络整体架构1.输入层2. 卷积层3.池化层4.全连接层 5.神经网络6.经典网络1.Alexnet2. Vgg3.Resnet 残差网络-特征提取 7.感受野 前言 大纲目录 首先链接图像颜色通道 1.卷积网络和传统网络区别 右边的就是CNN&#xff0c;卷…...

黑马JVM总结(八)

&#xff08;1&#xff09;StringTable面试题 1.8 1.6时 &#xff08;2&#xff09;StringTable的位置 jvm1.6时StringTable是常量池的一部分&#xff0c;它随着常量池存储在永久代当中&#xff0c;在1.7、1.8中从永久代变成了堆中&#xff0c;为什么做这个更改呢&#xff1f…...

开源网安入选广东省网络空间安全标准化技术委员会新技术及应用安全技术工作组成员单位

近日&#xff0c;第二届广东省网络空间安全标准化技术委员会&#xff08;GD/TC 124&#xff09;&#xff08;以下简称省网安标委&#xff09;正式成立。为进一步发挥省网安标委在支撑网络强国建设、推进网络安全产业高质量发展过程中&#xff0c;示范引领核心技术攻关、创新产品…...

Nginx配置指南:如何定位、解读与优化Linux上的Nginx设置

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…...

辉瑞与吉利德科学:制药巨头的新冠病毒之战

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;猛兽财经认为&#xff0c;华尔街低估了辉瑞&#xff08;PFE&#xff09;和吉利德科学&#xff08;GILD&#xff09;的前景&#xff0c;因为它们在开发新冠病毒疫苗和药物方面都…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...