你看这个spring的aop它又大又宽
aop🚓
- AOP 分类
- AspectJ | 高级但是难用
- Spring AOP | 易用但仅支持方法
- aop 原理
明月几时有,把酒问青天。——唐代李白《将进酒》
AOP 分类
在 Spring Boot 中,AOP 的实现主要有以下几种:
-
基于 AspectJ 的 AOP:这是一种基于 Java 语言扩展(Java Language Extension,JLE)的 AOP 实现方式,支持静态织入和动态织入两种方式。
-
Spring AOP:这是 Spring 框架自带的 AOP 实现方式,基于动态代理机制实现,只支持方法级别的切面。
-
自定义注解实现 AOP:通过自定义注解和 AOP 技术实现业务逻辑和切面逻辑的分离,便于代码的维护和扩展。
其中,基于 AspectJ 的 AOP 功能最为强大,但使用难度较大;Spring AOP 简单易用,但功能有一定限制;自定义注解实现 AOP 灵活性较高,但需要自行实现 AOP 切面逻辑。在实际开发中,应根据项目需要选择合适的 AOP 实现方式。
Spring AOP 是基于代理的 AOP,而 AspectJ 是基于字节码的 AOP
Spring AOP 和 AspectJ 都是 Spring Framework 中的 AOP 实现方式。Spring AOP 是基于代理的 AOP,而 AspectJ 是基于字节码的 AOP。
在 Spring Boot 中,默认情况下使用的是 Spring AOP。如果需要使用 ,可以通过在启动类上添加 @EnableAspectJAutoProxy(proxyTargetClass = true)
注解来开启。
如果需要使用 AspectJ, 需要引入 AspectJ jar包
@EnableAspectJAutoProxy 不是用来开启 AspectJ 的吗
配置 @EnableAspectJAutoProxy, 不引入 AspectJ jar包的情况下就使用 Spring AOP
@EnableAspectJAutoProxy
注解可以用来开启 AspectJ 的支持,但是它也是用来开启 Spring AOP 的。
在 Spring 中,Spring AOP 和 AspectJ 都是实现 AOP 的方式之一。@EnableAspectJAutoProxy
注解用来开启 Spring AOP 的支持,如果在注解中设置 proxyTargetClass=true
,则会使用 CGLIB 来创建代理对象,否则会使用 JDK 的动态代理。
当然,在 Spring Boot 中,如果需要使用 AspectJ,也可以在启动类上添加 @EnableAspectJAutoProxy(proxyTargetClass = true)
注解来开启 AspectJ 支持
AspectJ | 高级但是难用
AspectJ中的静态织入和动态织入
AspectJ 是一个基于 Java 语言的切面编程框架,它提供了两种切面织入方式:静态织入和动态织入。
静态织入是指在编译期间将切面代码织入到目标类中,生成一个新的字节码文件。在运行期间,JVM 加载这个字节码文件,并且这个字节码文件包含了目标类和切面代码,从而实现对目标类的增强。静态织入的优点是织入后的代码执行效率高,缺点是需要在编译期间进行织入,增加了额外的工作量和复杂度。
动态织入是指在运行期间将切面代码织入到目标类中,不需要在编译期间进行修改。在运行期间,通过 JVM 提供的动态代理技术或字节码生成技术,将切面代码织入到目标类中,从而实现对目标类的增强。动态织入的优点是织入更加灵活,可以在运行期间进行修改,缺点是织入后的代码执行效率相对较低。
在 AspectJ 中,静态织入和动态织入可以通过不同的方式实现。静态织入可以使用 AspectJ 编译器,将切面代码编译成字节码文件,并将其与目标类一起打包成一个 jar 包或 war 包,从而在运行期间加载这个包,实现对目标类的增强。动态织入可以使用 AspectJ 提供的 Runtime 织入功能,或者使用 Spring AOP 框架提供的动态代理技术,实现对目标类的增强。
AspectJ 支持更加灵活的切面编程,可以拦截不仅仅是方法级别的切面,还可以拦截字段、构造方法、类等级别的切面。
- 字段级别
要拦截字段级别的切面,可以使用 AspectJ 提供的 field 切点匹配器,例如:
javaCopy code
@Aspect
public class FieldAspect {@Before("get(* com.example.demo.model.User.name)")public void beforeFieldAccess(JoinPoint joinPoint) {// 拦截 User 类中的 name 字段的 getter 方法}}
在上面的示例中,使用 get 切点匹配器匹配 User 类中的 name 字段的 getter 方法,实现对字段级别的拦截。
- 构造方法级别
要拦截构造方法级别的切面,可以使用 AspectJ 提供的 initialization 切点匹配器,例如:
@Aspect
public class ConstructorAspect {@Before("execution(com.example.demo.model.User.new())")public void beforeConstructorExecution(JoinPoint joinPoint) {// 拦截 User 类的构造方法}}
在上面的示例中,使用 execution 切点匹配器匹配 User 类的构造方法,实现对构造方法级别的拦截。
- 类级别
要拦截类级别的切面,可以使用 AspectJ 提供的 type 切点匹配器,例如:
@Aspect
public class ClassAspect {@Before("execution(* com.example.demo.service.*.*(..)) && type(service)")public void beforeServiceMethodExecution(JoinPoint joinPoint) {// 拦截 com.example.demo.service 包下的所有方法,并且方法所属的类必须被 @Service 注解标注}}
在上面的示例中,使用 execution 切点匹配器匹配 com.example.demo.service 包下的所有方法,并且方法所属的类必须被 @Service 注解标注,实现对类级别的拦截。
需要注意的是,AspectJ 的切面匹配器比 Spring AOP 更加灵活,可以匹配更多的切点。但是,AspectJ 的使用需要在编译期间进行织入,因此相对来说也更加复杂和耗费资源。在实际使用中,需要根据实际需求选择使用 Spring AOP 还是 AspectJ。
使用 AspectJ, 要引入什么jar包
Spring Boot 默认使用 Spring AOP,如果要使用 AspectJ,需要手动引入 AspectJ 相关的依赖。
可以在 pom.xml
文件中添加以下依赖:
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.7</version>
</dependency>
其中,aspectjweaver
依赖是必须的,它包含了 AspectJ 的运行时环境;aspectjrt
依赖是可选的,它包含了 AspectJ 的运行时库,如果使用了 AspectJ 的注解,建议添加该依赖。
在添加了依赖后,可以在启动类上添加 @EnableAspectJAutoProxy
注解开启 AspectJ 支持,或者在切面类上使用 @Aspect
注解定义切面类。
Spring AOP | 易用但仅支持方法
Spring AOP 只支持方法级别的切面
Spring AOP 只支持方法级别的切面指的是,Spring AOP 只能拦截方法的执行,而不能拦截其他级别的切面,例如字段级别、构造方法级别、类级别等。
这是因为 Spring AOP 的实现方式是基于 JDK 动态代理或 CGLIB 字节码生成技术的,而 JDK 动态代理和 CGLIB 都是基于方法级别的。在使用 JDK 动态代理时,代理对象必须实现一个或多个接口,而接口是方法集合的抽象,因此只能对接口中定义的方法进行拦截;在使用 CGLIB 字节码生成技术时,会生成一个新的类作为代理类,该类是原始类的子类,因此只能拦截原始类中的方法,无法拦截字段、构造方法等。
不过,Spring AOP 还提供了其他的一些拦截点,例如:
-
Bean 生命周期事件:可以在 Bean 初始化前后、销毁前后等事件中执行通知。
-
AspectJ 注解:可以使用 @AspectJ 注解来实现更为灵活的切面拦截,支持字段级别、构造方法级别、类级别等切入点。
需要注意的是,使用 AspectJ 注解时,需要添加相应的 AspectJ 依赖,并配置 AspectJ 编译器,以支持注解的解析和织入。
aop 原理
通过 @EnableAspectJAutoProxy 将aop的功能通过bean后置处理器, 关联到我们的IOC容器中
EnableAspectJAutoProxy 的目的是为了导入 AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator 又是bean后置处理器, 这不就挂钩上了吗
史上最完整的AOP底层原理_哔哩哔哩_bilibili
一文吃透spring aop底层原理_spring aop的底层原理_吴法刚的博客-CSDN博客
那么AOP具体是如何在我体内运行的呢?在我启动时会创建IOC容器, 同时将我体内的bean进行三个连续的动作,
-
构造
-
填充
-
属性初始化
AOP功能就是通过我体内一个专门处理AOP的bean后置处理器 DefaultAdvisorAutoProxyCreator 进行方法增强的,
可以算作IOC容器的附加功能, 所有的后置处理器都在bean构造完, 并且填充了属性之后执行
-
填充了属性之后执行
-
在每一个bean初始化之后都会调用这个后置处理器的postProcessorAfterInitialization 方法, 在这个方法里为需要使用AOP的bean创建代理对象。
-
先通过getAdvicesAndAdvisorsForBean方法, 获取所有的增强Advice, 同时判断当前bean是否满足我们配置的切面条件
如果满足条件的话, 就会为这个bean构造代理对象来实现AOP
为了更统一更方便的构造代理对象, 我会先搭建一个专门用来构造生产代理对象的工厂, proxyFactory, 我会告诉这个工厂具体选择哪种方式进行代理, 分别是cglib和jdkProxy。
通过添加@EnableAspectJAutoProxy注解, 并且将其中proxyTargetClass配置改为 true 强制使用cglib。
当然啦在spring boot中默认就是使用cglib, 不过只有这个配置为false, 同时该类实现了任意接口才会使用jdkProxy, 否则还是会使用cglib方式。
ProxyFactory知道使用哪种方式之后, 就会构造jdkDynamicAopProxy或者cglibAopProxy, 然后就可以通过他们的getProxy方法获得真正的代理对象。
jdkDynamicAopProxy
先说相对简单, 而且即将被我无情放弃的jdkDynamicAopProxy, 在getProxy中会构造一个实现同样bean接口的代理对象, 将真实bean作为代理, 对象中的一个成员变量。
在调用bean方法的时候就会执行代理对象中的 invoke 方法
这个 invoke 方法只有两步,
-
我会通过之前提到的execution表达式, 获取所有与该方法匹配的所有增强方法, 并将它们组成调用链同时进行排序
-
开始按顺序执行这些调用链, 这里的调用方式就是经典的责任链模式, 在调用中间会插入bean 执行bean真实的方法
cglibAopProxy
最为常用的cglibAopProxy, 同样会在getProxy方法中构造代理对象
用增强器 Enhancer 来设置代理基本信息以及增强方法的调用链
接着执行 Enhancer create方法来生成代理对象
和jdkDynamicAopProxy不同的是cglib是基于jdk rt jar包中的asm来生成一组新的class文件, 然后实例化它的对象, 所以对于没有实现接口的bean也可以生成代理对象
在调用bean方法的时候, 会先执行代理对象的intercept方法, 与jdkProxy一样, 也会通过责任链来执行所有的方法增强。
相关文章:

你看这个spring的aop它又大又宽
aop🚓AOP 分类AspectJ | 高级但是难用Spring AOP | 易用但仅支持方法aop 原理明月几时有,把酒问青天。——唐代李白《将进酒》 AOP 分类 在 Spring Boot 中,AOP 的实现主要有以下几种: 基于 AspectJ 的 AOP:这是一种基…...

设计模式-创建-单例模式
4.1.1 模式介绍 定义 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,此模式保证某个类在运行期间,只有一个实例对外提供服务,而这个类被称为单例类。 作用 保证一个类只有一个实例为该实例提供一个全…...

使用mybatis-plus-generator配置一套适合你的CRUD
1、maven引入 mybatis-plus-generator 和模板引擎,你也可以使用freemarker之类的,看个人 <!-- mybatisplus代码生成器 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactI…...
MATLAB实现各种离散概率密度函数(概率密度/分布/逆概率分布函数)
MATLAB实现各种离散概率密度函数(概率密度/分布/逆概率分布函数) 1 常见离散概率分布的基本信息2 常见离散概率分布计算及MATLAB实现2.1 二项分布(Binomial Distribution)2.1.1 常用函数2.2 负二项分布(Negative Binomial Distribution)2.2.1 常用函数2.3 几何分布(Geom…...
指针的基本知识
我们不会用bit去表达一个数据,因为只能放0和1,能表达的数据太少了,内存地址最小单位是字节 11111111 0x0011 1字节8bit,8bit才算作一个地址,地址是以字节为最小单位&#…...

当你的IDE装上GPT
文章目录前言下载安装使用步骤前言 我们可能要从“CV”工程师变成“KL工程师了,为什么叫”KL“工程师呢, 因为只要K和L两个指令就可以直接生成代码、修改代码,哪行代码不会点哪里,他都给你解释得明明白白。 提示:以下…...

一图看懂 pathlib 模块:面向对象的文件系统路径, 资料整理+笔记(大全)
本文由 大侠(AhcaoZhu)原创,转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 pathlib 模块:面向对象的文件系统路径, 资料整理笔记(大全)摘要模块图类关系图模块全展开【pathlib】统计常量intbooltuple模块9 fnmatc…...

前端如何将node.js 和mongodb部署到linux服务器上
本文首发自掘金。 记录了我第一次成功部署node.js 和mongodb到linux服务器上了,期间也遇到一些小坑,但是网上各位大佬记录的文章帮了大忙,所以我也将过程记录了下来。 安装Node 使用nvm linux上安装node,肯定首选nvmÿ…...
mysql数据迁移
背景:随着时间的推移,交易系统中的订单表越来越大,目前达到500w数据。为了防止数据量过大导致的查询性能问题,现将订单表进行拆分,分为实时库和历史库。实时库保留近6个月的数据,用于退款业务需求ÿ…...
【4.3蓝桥备战】小朋友崇拜圈、正则问题
文章目录小朋友崇拜圈正则问题小朋友崇拜圈 小朋友崇拜圈 - 蓝桥云课 (lanqiao.cn) 拿到这道题要先把题目读懂。 下面的一行是表示:编号为i的小朋友,崇拜的对象为编号为path[i]的小朋友。 本题应该使用DFS,深度优先遍历找到可以成环的崇拜圈…...
MySQL读写分离中间件
1.什么是读写分离中间件? 就是实现当[写]的时候转发到主库,当[读]的时候转发到从库的工具。 很类似学习过的proxy,比如nginx proxy做动静分离. 2.为什么要实现读写分离? 1)让主库专注于写,因为读可以有很多从库可以干…...

【Spring源码设计模式】单例模式外带设计模式的单例模式
Bean的概念 是Spring框架在运行时管理的对象,是任何引用程序的基本构建块。 Bean的属性 id属性:Bean的唯一标志名,必须以字母开头且不包含特殊字符 class属性:用来定义类的全限定名(包名 类名) name属性…...

go并发编程 —— singleflight设计模式
什么是singleflight singleflight是一种并发编程设计模式,将同一时刻的多个并发请求合并成一个请求,以减少对下游服务的压力 为什么叫singleflight fly可以理解为请求数,singleflight就是单个请求 使用场景 该模式主要用于防止缓存击穿 …...

【LeetCode】二叉树的中序遍历(递归,迭代,Morris遍历)
目录 题目要求:给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 方法一:递归 方法二:迭代 思路分析: 复杂度分析 代码展示: 方法三:Morris 遍历 思路分析: 复杂度分析…...

银行数字化转型导师坚鹏:数字化转型背景下的银行柜员提升之道
数字化转型背景下的银行柜员提升之道 课程背景: 很多银行都在开展银行数字化运营工作,目前存在以下问题急需解决: l 不清楚银行数字化运营包括哪些关键工作? l 不清楚银行数字化运营工作的核心方法论? l 不清楚银行数字…...

ChatGPT的平替来了?一文总结 ChatGPT 的开源平替,你值得拥有
文章目录【AIGC精选】总结 ChatGPT 的开源平替,你值得拥有1.斯坦福发布 Alpaca 7B,性能匹敌 GPT-3.52.弥补斯坦福 Alpaca 中文短板,中文大模型 BELLE 开源3.国产AI大模型 ChatGLM-6B 开启内测4.中文 Alpaca 模型 Luotuo 开源5. ChatGPT 最强竞…...

关于数据同步工具DataX部署
1.DataX简介 1.1 DataX概述 DataX 是阿里巴巴开源的一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 源码地址:GitHub - alibaba/DataX: DataX是…...
如何开发JetBrains插件
1 标题安装 IntelliJ IDEA 如果您还没有安装 IntelliJ IDEA,从官方网站下载并安装 IntelliJ IDEA Community Edition(免费)或 Ultimate Edition(付费)。 2 创建插件项目 在 IntelliJ IDEA 中,创建一个新…...

企业采购成本管理的难题及解决方案
企业采购成本控制是企业管理中的一个重要方面,也是一个不容易解决的难题。企业采购成本控制面临的难题包括以下几个方面: 1、采购流程复杂 企业采购通常需要经过一系列的流程,包括采购计划、采购申请、报价、比价、议标、合同签订、验收、付…...
龙蜥白皮书精选:基于 SM4 算法的文件加密(fscrypt)实践
文/张天佳 通常我们会以文件作为数据载体,使用磁盘,USB 闪存,SD 卡等存储介质进行数据存储,即便数据已经离线存储,仍然不能保证该存储介质不会丢失,如果丢失那么对于我们来说有可能是灾难性的事件。因此对…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...