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

你看这个spring的aop它又大又宽

aop🚓

        • AOP 分类
        • AspectJ | 高级但是难用
        • Spring AOP | 易用但仅支持方法
        • aop 原理

明月几时有,把酒问青天。——唐代李白《将进酒》

AOP 分类

在 Spring Boot 中,AOP 的实现主要有以下几种:

  1. 基于 AspectJ 的 AOP:这是一种基于 Java 语言扩展(Java Language Extension,JLE)的 AOP 实现方式,支持静态织入和动态织入两种方式。

  2. Spring AOP:这是 Spring 框架自带的 AOP 实现方式,基于动态代理机制实现,只支持方法级别的切面。

  3. 自定义注解实现 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 支持更加灵活的切面编程,可以拦截不仅仅是方法级别的切面,还可以拦截字段、构造方法、类等级别的切面。

  1. 字段级别

要拦截字段级别的切面,可以使用 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 方法,实现对字段级别的拦截。

  1. 构造方法级别

要拦截构造方法级别的切面,可以使用 AspectJ 提供的 initialization 切点匹配器,例如:

@Aspect
public class ConstructorAspect {@Before("execution(com.example.demo.model.User.new())")public void beforeConstructorExecution(JoinPoint joinPoint) {// 拦截 User 类的构造方法}}

在上面的示例中,使用 execution 切点匹配器匹配 User 类的构造方法,实现对构造方法级别的拦截。

  1. 类级别

要拦截类级别的切面,可以使用 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 还提供了其他的一些拦截点,例如:

  1. Bean 生命周期事件:可以在 Bean 初始化前后、销毁前后等事件中执行通知。

  2. AspectJ 注解:可以使用 @AspectJ 注解来实现更为灵活的切面拦截,支持字段级别、构造方法级别、类级别等切入点。

需要注意的是,使用 AspectJ 注解时,需要添加相应的 AspectJ 依赖,并配置 AspectJ 编译器,以支持注解的解析和织入。

aop 原理

通过 @EnableAspectJAutoProxy 将aop的功能通过bean后置处理器, 关联到我们的IOC容器中

EnableAspectJAutoProxy 的目的是为了导入 AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator 又是bean后置处理器, 这不就挂钩上了吗

史上最完整的AOP底层原理_哔哩哔哩_bilibili

一文吃透spring aop底层原理_spring aop的底层原理_吴法刚的博客-CSDN博客

那么AOP具体是如何在我体内运行的呢?在我启动时会创建IOC容器, 同时将我体内的bean进行三个连续的动作,

  1. 构造

  2. 填充

  3. 属性初始化

AOP功能就是通过我体内一个专门处理AOP的bean后置处理器 DefaultAdvisorAutoProxyCreator 进行方法增强的,

可以算作IOC容器的附加功能, 所有的后置处理器都在bean构造完, 并且填充了属性之后执行

  1. 填充了属性之后执行

  2. 在每一个bean初始化之后都会调用这个后置处理器的postProcessorAfterInitialization 方法, 在这个方法里为需要使用AOP的bean创建代理对象

  3. 先通过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 方法只有两步,

  1. 我会通过之前提到的execution表达式, 获取所有与该方法匹配的所有增强方法, 并将它们组成调用链同时进行排序

  2. 开始按顺序执行这些调用链, 这里的调用方式就是经典的责任链模式, 在调用中间会插入bean 执行bean真实的方法

cglibAopProxy

最为常用的cglibAopProxy, 同样会在getProxy方法中构造代理对象

用增强器 Enhancer 来设置代理基本信息以及增强方法的调用链
接着执行 Enhancer create方法来生成代理对象

和jdkDynamicAopProxy不同的是cglib是基于jdk rt jar包中的asm来生成一组新的class文件, 然后实例化它的对象, 所以对于没有实现接口的bean也可以生成代理对象

在调用bean方法的时候, 会先执行代理对象的intercept方法, 与jdkProxy一样, 也会通过责任链来执行所有的方法增强。

相关文章:

你看这个spring的aop它又大又宽

aop&#x1f693;AOP 分类AspectJ | 高级但是难用Spring AOP | 易用但仅支持方法aop 原理明月几时有&#xff0c;把酒问青天。——唐代李白《将进酒》 AOP 分类 在 Spring Boot 中&#xff0c;AOP 的实现主要有以下几种&#xff1a; 基于 AspectJ 的 AOP&#xff1a;这是一种基…...

设计模式-创建-单例模式

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

使用mybatis-plus-generator配置一套适合你的CRUD

1、maven引入 mybatis-plus-generator 和模板引擎&#xff0c;你也可以使用freemarker之类的&#xff0c;看个人 <!-- 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去表达一个数据&#xff0c;因为只能放0和1&#xff0c;能表达的数据太少了&#xff0c;内存地址最小单位是字节 11111111 0x0011 1字节8bit,8bit才算作一个地址&#xff0c;地址是以字节为最小单位&#…...

当你的IDE装上GPT

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

一图看懂 pathlib 模块:面向对象的文件系统路径, 资料整理+笔记(大全)

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

前端如何将node.js 和mongodb部署到linux服务器上

本文首发自掘金。 记录了我第一次成功部署node.js 和mongodb到linux服务器上了&#xff0c;期间也遇到一些小坑&#xff0c;但是网上各位大佬记录的文章帮了大忙&#xff0c;所以我也将过程记录了下来。 安装Node 使用nvm linux上安装node&#xff0c;肯定首选nvm&#xff…...

mysql数据迁移

背景&#xff1a;随着时间的推移&#xff0c;交易系统中的订单表越来越大&#xff0c;目前达到500w数据。为了防止数据量过大导致的查询性能问题&#xff0c;现将订单表进行拆分&#xff0c;分为实时库和历史库。实时库保留近6个月的数据&#xff0c;用于退款业务需求&#xff…...

【4.3蓝桥备战】小朋友崇拜圈、正则问题

文章目录小朋友崇拜圈正则问题小朋友崇拜圈 小朋友崇拜圈 - 蓝桥云课 (lanqiao.cn) 拿到这道题要先把题目读懂。 下面的一行是表示&#xff1a;编号为i的小朋友&#xff0c;崇拜的对象为编号为path[i]的小朋友。 本题应该使用DFS&#xff0c;深度优先遍历找到可以成环的崇拜圈…...

MySQL读写分离中间件

1.什么是读写分离中间件&#xff1f; 就是实现当[写]的时候转发到主库&#xff0c;当[读]的时候转发到从库的工具。 很类似学习过的proxy,比如nginx proxy做动静分离. 2.为什么要实现读写分离&#xff1f; 1&#xff09;让主库专注于写&#xff0c;因为读可以有很多从库可以干…...

【Spring源码设计模式】单例模式外带设计模式的单例模式

Bean的概念 是Spring框架在运行时管理的对象&#xff0c;是任何引用程序的基本构建块。 Bean的属性 id属性&#xff1a;Bean的唯一标志名&#xff0c;必须以字母开头且不包含特殊字符 class属性&#xff1a;用来定义类的全限定名&#xff08;包名 类名&#xff09; name属性…...

go并发编程 —— singleflight设计模式

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

【LeetCode】二叉树的中序遍历(递归,迭代,Morris遍历)

目录 题目要求&#xff1a;给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 方法一&#xff1a;递归 方法二&#xff1a;迭代 思路分析&#xff1a; 复杂度分析 代码展示&#xff1a; 方法三&#xff1a;Morris 遍历 思路分析&#xff1a; 复杂度分析…...

银行数字化转型导师坚鹏:数字化转型背景下的银行柜员提升之道

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

ChatGPT的平替来了?一文总结 ChatGPT 的开源平替,你值得拥有

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

关于数据同步工具DataX部署

1.DataX简介 1.1 DataX概述 DataX 是阿里巴巴开源的一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 源码地址&#xff1a;GitHub - alibaba/DataX: DataX是…...

如何开发JetBrains插件

1 标题安装 IntelliJ IDEA 如果您还没有安装 IntelliJ IDEA&#xff0c;从官方网站下载并安装 IntelliJ IDEA Community Edition&#xff08;免费&#xff09;或 Ultimate Edition&#xff08;付费&#xff09;。 2 创建插件项目 在 IntelliJ IDEA 中&#xff0c;创建一个新…...

企业采购成本管理的难题及解决方案

企业采购成本控制是企业管理中的一个重要方面&#xff0c;也是一个不容易解决的难题。企业采购成本控制面临的难题包括以下几个方面&#xff1a; 1、采购流程复杂 企业采购通常需要经过一系列的流程&#xff0c;包括采购计划、采购申请、报价、比价、议标、合同签订、验收、付…...

龙蜥白皮书精选:基于 SM4 算法的文件加密(fscrypt)实践

文/张天佳 通常我们会以文件作为数据载体&#xff0c;使用磁盘&#xff0c;USB 闪存&#xff0c;SD 卡等存储介质进行数据存储&#xff0c;即便数据已经离线存储&#xff0c;仍然不能保证该存储介质不会丢失&#xff0c;如果丢失那么对于我们来说有可能是灾难性的事件。因此对…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...