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

【Spring】Spring AOP原理

目录

前言

代理模式

静态代理

优缺点

动态代理

JDK动态代理

工作原理

JDK动态原理实现关键步骤

CGLib动态代理 

 CGLIB动态代理实现关键步骤

总结


前言

在上一篇中,我们讲解了什么是AOP,以及Spring AOP是如何使用的,那么本篇我们就来学习一下Spring AOP的原理,也就是Spring是如何实现AOP的。

Spring AOP是基于动态代理来实现AOP的,什么是动态代理呢?动态代理其实是一种代理模式。

代理模式

代理模式,又可以称为委托模式,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

简单来说:代理模式可以在不改变原对象的基础上,通过引入一个代理对象来间接访问原对象,从而实现堆原对象的某些操作的控制

使用代理前:

使用代理后:

 在生活中,能够体现代理模式的有很多,如房屋中介。当我们想要租房的时候,如果我们直接去找房东,如果房东一个个带我们去看,就会很浪费时间,若房东比较忙,就有可能会处理不过来,所以房东就会把租房这件事情交给中介,而我们直接去找中介,并提出我们的需求,中介就会帮助我们找到合适的房子。这样就极大的方便了我们租房的流程。

代理模式中主要角色:

  • Subject:业务接口类,可以是抽象类或者接口(不一定有);
  • RealSubject:业务实现类,具体的业务逻辑,也就是被打理对象,如房东;
  • Proxy:代理类。RealSubject 的代理,通过中介体现。

代理模式我们可以分为两种:静态代理动态代理

在静态代理中,我们对目标对象中的每个方法的增强都是手动完成的,耦合性高,而动态代理,则是通过在运行时创建一个子类实例来实现的,可以更加灵活地实现代理。

  • 静态代理:在编译时就已经确定的代理类,代理类和真实主题类通常实现相同的接口。
  • 动态代理:在运行时利用反射机制动态生成代理类,不需要先定义代理类,而是在运行时根据指定的类和接口动态生成代理类。

静态代理

静态代理是指代理类在程序运行前就已经定义好,与目标类的关系在运行前就确定

在静态代理中,真实主题类和代理类都实现一个相同的接口,代理类通过调用真实主题类的方法来实现接口中定义的业务逻辑,同时可以在调用前后增加额外的操作。

优缺点

  • 优点:简单直观,易于理解和实现;
  • 缺点:
    • 每个目标类都需要创建对应的代理类,如果目标类太多,就会导致类的数量急剧增加,增加了系统的复杂性;
    • 代理类是硬编码,不灵活。

我们以前面讲的中介为例:

在用户租房前,中介和房东需要先协商好,中介就能帮助房东出租或出售房子,当有人去找中介讲需求的时候,中介就可以直接联系客户和房东进行对接。

通过代码展示:

定义一个接口(房东想要的事,也就是中介要做的事):

package com.example.demo.aspect;public interface HouseSubject {void rent();
}

房东:

package com.example.demo.aspect;public class RealHouseSubject implements HouseSubject{@Overridepublic void rent() {System.out.println("我要出租房子");}
}

中介:

package com.example.demo.aspect;public class ProxyHouse implements HouseSubject{private RealHouseSubject realHouseSubject;public ProxyHouse(RealHouseSubject realHouseSubject){this.realHouseSubject = realHouseSubject;}@Overridepublic void rent() {System.out.println("我是中介,开始代理");realHouseSubject.rent();System.out.println("我是中介,结束代理");}
}

客户租房:

通过这个案例,我们能够进一步理解静态代理。

那么如果房东现在想要对房子进行出租,那么中介和房东就需要再一次协商。

public interface HouseSubject {void rent();void sale();
}

中介:

package com.example.demo.aspect;public class ProxyHouse implements HouseSubject{private RealHouseSubject realHouseSubject;public ProxyHouse(RealHouseSubject realHouseSubject){this.realHouseSubject = realHouseSubject;}@Overridepublic void rent() {System.out.println("我是中介,开始代理");realHouseSubject.rent();System.out.println("我是中介,结束代理");}@Overridepublic void sale() {System.out.println("我是中介,开始代理");realHouseSubject.sale();System.out.println("我是中介,结束代理");}
}

房东:

package com.example.demo.aspect;public class RealHouseSubject implements HouseSubject{@Overridepublic void rent() {System.out.println("我要出租房子");}@Overridepublic void sale() {System.out.println("我要出售房子");}
}

客户买房:

package com.example.demo.aspect;public class Main {public static void main(String[] args) {RealHouseSubject realHouseSubject = new RealHouseSubject();ProxyHouse proxyHouse = new ProxyHouse(realHouseSubject);
//        proxyHouse.rent();proxyHouse.sale();}
}

我们可以看到,当我们想要对业务进行修改的时候,那么对应的其它两个实现类进行修改,若增加的业务越多,修改的就越多。

那么有没有一种方法?让他们通过一个代理类来实现呢?这就需要用到动态代理了。

动态代理

动态代理是在运行时利用反射机制动态生成代理类的代理方式,不需要事先定义代理类,而是在运行时根据指定的类和接口动态生成代理类。

动态代理不需要修改原始对象,就能对对象的功能进行增强,例如实现横切关注点,日志记录、性能监控、事务管理等。

常见的动态代理有 JDK代理 CGLib代理

JDK动态代理

JDK动态代理是Java标准库中提供的一种动态代理机制,允许在运行时动态生成实现了一个或多个接口的代理类,而无需事先知道具体的类

工作原理
  • 使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口实现。
  • 目标类必须实现一个或多个接口
  • 代理类在运行时生成,实现了与目标类相同的接口。
  • 通过实现 InvocationHandler 接口,可以自定义方法调用的行为,即在调用目标方法前后添加额外逻辑

不过JDK动态代理其实有个缺点:只能代理实现了接口的类,对于没有实现接口的类,是不能代理实现的

JDK动态原理实现关键步骤
  • 定义接口:首先需要定义一个接口,该接口将由目标对象和代理对象实现。
  • 创建目标对象:需要先创建目标对象的实例,该实例将被代理对象代理。
  • 实现 InvocationHandler 接口:创建一个实现  java.lang.reflect.InvocationHandler 接口的类,该类将定义代理对象的方调用逻辑。在实现该接口的类中,需要重写 invoke() 方法,以便在目标对象的方法调用前后执行额外的业务逻辑。
  • 创建代理对象:使用 java.lang.reflect.Proxy 类 和 InvocationHandler 对象创建代理对象。具体来说就是要调用 Proxy类中的静态方法newProxyInstance() 创建一个代理对象,该实例将调用InvocationHandler对象的invoke() 方法来处理方法调用
  • 使用代理对象:使用代理对象调用目标对象的方法时,会在方法执行前后执行额外的逻辑。

我们利用中介的例子来用代码实现:

实现接口

package com.example.demo.aspect;public interface HouseSubject {void rent();void sale();
}

创建目标对象

package com.example.demo.aspect;public class RealHouseSubject implements HouseSubject{@Overridepublic void rent() {System.out.println("我要出租房子");}@Overridepublic void sale() {System.out.println("我要出售房子");}
}

 创建一个实现InvocationHandler接口的代理类:

package com.example.demo.aspect;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class JDKInvocationHandler implements InvocationHandler {private Object target;public JDKInvocationHandler(Object target){this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//目标对象执行之前,代理增强System.out.println("我是中介,开始代理");//通过反射执行被代理对象的方法Object result=method.invoke(target, args);//目标对象执行完成之后,代理增强System.out.println("我是中介,结束代理");return result;}
}

创建代理对象并调用

package com.example.demo.aspect;
import java.lang.reflect.Proxy;
public class DynamicMain {public static void main(String[] args) {HouseSubject target = new RealHouseSubject();HouseSubject proxy= (HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[]{HouseSubject.class},new JDKInvocationHandler(target));proxy.rent();}
}

结果

那么上面这些InvocationHandler接口以及Proxy到底是什么呢?

InvocationHandler接口是java动态代理的关键接口之一,定义了一个单一方法 invoke() 方法,该方法是代理示例调用的中心分发点。当代理实例的任意方法被调用时,调用会自动委托给关联的 InvocationHandler 实例的 invoke() 方法。

    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
  • proxy:就是要代理对象本身,可以用来调用目标对象的其他方法或者属性;
  • method被调用的方法的 Mathod 对象,提供了关于方法的详细信息,如方法名、参数类型等;
  • args调用方法时传递的参数数组

Proxy类是位于 java.lang.reflect 包中的一个类,提供了创建动态代理类和实例的静态方法。它是JDK动态代理机制的入口点。Proxy类没有公共的构造函数,所以不能直接实例化。但我们可以用它里面的 newProxyInstance 来创建代理实例。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler invocationHandler)throws IllegalArgumentException
  • loader定义了代理类的类加载器,通常是目标类的类加载器;
  • interfaces代理类需要实现的接口数组,代理类中会实现这些接口中定义的所有方法;
  • invocationHandler:一个InvocationHandler示例,定义了当代理实例的方法被调用时的处理逻辑

CGLib动态代理 

JDK动态代理有一个致命的问题就是只能代理实现了接口的类。

但是在有些情况下,我们的业务代码是直接实现的,并没有接口定义,那就不能实现JDK代理了,为了解决这个问题,我们可以用CGLIB动态代理机制来解决。

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,通过字节码技术在运行时为没有实现接口的目标类生成子类作为代理类

CGLIB能代理任何未实现接口的类,是因为CGLIB是通过继承方式生成一个目标类的子类,重写父类的方法并在方法中加入增强逻辑实现动态代理的

注意CGLIB动态代理要求被代理的目标类不能声明为final类,并且方法也不能是final方法,否则无法被CGLIB成功继承和重写

 CGLIB动态代理实现关键步骤
  1. 添加CGLIB库:我们需要将CGLIB依赖引入;
  2. 创建目标对象:创建一个需要被代理的类;
  3. 实现接口:自定义 MethodInterceptor 并重写 intercept() 方法,intercept() 用于增强目标方法,和JDK动态代理的 invoke() 方法类似;
  4. 创建代理对象:通过调用Enhancer对象中的create()方法创建代理对象;
  5. 使用代理对象:利用代理对象来调用目标对象的方法,在方法调用前后会执行额外的逻辑。

演示:

添加依赖

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

创建目标类

package com.example.demo.aspect;public class RealHouseSubject implements HouseSubject{@Overridepublic void rent() {System.out.println("我要出租房子");}@Overridepublic void sale() {System.out.println("我要出售房子");}
}

实现MethodInterceptor接口

package com.example.demo.aspect;import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGLibInterceptor implements MethodInterceptor {private Object target;public CGLibInterceptor(Object target) {this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//跟JDK 代理一样,代理增强的逻辑写在这个方法中System.out.println("我是中介,开始代理");Object invoke = method.invoke(target, objects);System.out.println("我是中介,结束代理");return invoke;}
}

使用

package com.example.demo.aspect;import net.sf.cglib.proxy.Enhancer;
public class DynamicMain {public static void main(String[] args) {HouseSubject target = new RealHouseSubject();HouseSubject proxy= (HouseSubject) Enhancer.create(target.getClass(),new CGLibInterceptor(target));proxy.rent();}
}

 


总结

Spring AOP是如何实现的?

Spring AOP是基于动态代理实现的,有两种方式:基于JDK动态代理实现和基于CGLIB动态代理实现,运行时使用哪种方法与项目配置和代理的对象有关。

Spring AOP的实现方式常见的有几种?

Spring AOP常见的实现方式有两种:1、基于注解@Aspect来实现的;2、基于自定义注解实现,还有一些更原始的方式,如基于代理、基于XML配置等

JDK动态代理和CGLIB动态代理有什么区别以及如何选择?

  • 实现方式:JDK代理是基于接口实现的,必须先定义接口;CGLIB代理是直接基于被代理类实现的,不需要定义接口。
  • 代理机制:JDK动态代理机制是委托机制,通过委托handler调用原始实现类方法;而CGLIB则使用继承机制,被代理类和代理类是继承关系,因此代理类对象可以直接赋值给代理类类型的变量。总的来说:JDK代理是基于接口实现的,CGLIB是基于继承实现的
  • 选择:如果需要代理实现了接口的类,且对性能要求不是特别高,可以选择JDK代理;如果需要代理没有实现接口的类,或者对性能要求较高,可以用CGLIB代理。
  • 限制:JDK动态代理和CGLIB动态代理都不能代理 final 类和方法。对于JDK动态代理,final 类不能实现接口;对于CGLIB动态代理, final 类不能被继承。此外,两者都不能代理 final 方法,因为 final 方法不能被重写。

以上就是本篇所有内容~

若有不足,欢迎指正~ 

相关文章:

【Spring】Spring AOP原理

目录 前言 代理模式 静态代理 优缺点 动态代理 JDK动态代理 工作原理 JDK动态原理实现关键步骤 CGLib动态代理 CGLIB动态代理实现关键步骤 总结 前言 在上一篇中&#xff0c;我们讲解了什么是AOP&#xff0c;以及Spring AOP是如何使用的&#xff0c;那么本篇我们就…...

CentOS vs Ubuntu - 常用命令深度对比及最佳实践指南20250302

CentOS vs Ubuntu - 常用命令深度对比及最佳实践指南 引言 在 Linux 服务器操作系统领域&#xff0c;CentOS 和 Ubuntu 是广泛采用的发行版。它们在命令集、默认工具链及生态系统方面各有特点。本文深入剖析 CentOS 与 Ubuntu 在常用命令层面的异同&#xff0c;并结合实践案例…...

【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter27-工作者线程

二十七、工作者线程 工作者线程 前端开发者常说&#xff1a;“JavaScript 是单线程的。”这种说法虽然有些简单&#xff0c;但描述了 JavaScript 在浏览器中的一般行为。因此&#xff0c;作为帮助 Web 开发人员理解 JavaScript 的教学工具&#xff0c;它非常有用。单线程就意味…...

微信小程序 - 页面跳转(wx.navigateTo、wx.redirectTo、wx.switchTab、wx.reLaunch)

API 跳转 1、wx.navigateTo &#xff08;1&#xff09;基本介绍 功能&#xff1a;保留当前页面&#xff0c;跳转到应用内的某个页面&#xff0c;使用该方法跳转后可以通过返回按钮返回到原页面 使用场景&#xff1a;适用于需要保留当前页面状态&#xff0c;后续还需返回的情…...

vscode使用豆包MARSCode----集成doubao1.5 DeepSeekR1 DeepseekV3模型的ai编程插件

引入扩展 打开VSCode扩展窗口&#xff0c;在搜索窗口搜索MarsCode&#xff0c;找到MarsCode 插件单击「install」&#xff0c;完成安装&#xff0c;登录即可使用MarsCode 编程助手。 主要功能 主要快捷键 / explain 解释项目代码&#xff0c;AI 返回的内容有结构分类&#…...

C 语言共用体:深入理解与实践】

目录 一、引言 二、共用体的定义和基本语法 三、共用体的使用 3.1 声明共用体变量 3.2 给共用体成员赋值 3.3 共用体的内存布局 四、共用体的应用场景 4.1 节省内存空间 4.2 处理不同类型的数据 五、共用体使用的注意事项 六、总结 一、引言 在 C 语言中&#xff0c;共…...

Cherry Studio + 火山引擎 构建个人AI智能知识库

&#x1f349;在信息化时代&#xff0c;个人知识库的构建对于提高工作效率、知识管理和信息提取尤为重要。尤其是当这些知识库能结合人工智能来智能化地整理、分类和管理数据时&#xff0c;效果更为显著。我最近尝试通过 Cherry Studio 和 火山引擎 来搭建个人智能知识库&#…...

曹操智行构建国内首个全域自研闭环智驾生态

2月28日&#xff0c;曹操出行举办曹操智行自动驾驶平台上线仪式&#xff0c;宣布已成功构建国内首个“F立方”全域自研闭环智驾生态&#xff0c;同时在苏杭两地开启Robotaxi运营试点&#xff0c;并投放搭载吉利最新智驾系统的车辆。 此次试点运营&#xff0c;标志着曹操出行在…...

在 ASP.NET Core 中压缩并减少图像的文件大小

示例代码&#xff1a;https://download.csdn.net/download/hefeng_aspnet/90294127 在当今的数字时代&#xff0c;图像是 Web 应用程序和用户体验不可或缺的一部分。但是&#xff0c;处理大型图像文件可能会导致网页加载缓慢和更高的存储费用。为了解决这个问题&#xff0c;在…...

58、深度学习-自学之路-自己搭建深度学习框架-19、RNN神经网络梯度消失和爆炸的原因(从公式推导方向来说明),通过RNN的前向传播和反向传播公式来理解。

一、RNN神经网络的前向传播图如下&#xff1a; 时间步 t1: x₁ → (W_x) → [RNN Cell] → h₁ → (W_y) → y₁ ↑ (W_h) h₀ (初始隐藏状态) 时间步 t2: x₂ → (W_x) → [RNN Cell] → h₂ → (W_y) → y₂ ↑ (W_h) h₁ 时间…...

【Qt-信号与槽】connect函数的用法

&#x1f3e0;个人主页&#xff1a;Yui_ &#x1f351;操作环境&#xff1a;Qt Creator &#x1f680;所属专栏&#xff1a;Qt 文章目录 1.信号和槽的概念1.1 信号的本质1.2 槽的本质1.3 补充说明2. 信号和槽的使用2.1 connect函数介绍2.2 connect函数的简单使用2.2.1 图形化方…...

sql深入学习

文章目录 前言知识学习注释的两种形式字符型注入万能密码 布尔盲注报错注入堆叠注入时间盲注二次注入 小技巧 前言 这次学习建立在对数据库有基本的认识&#xff0c;了解基础的增删改查语句&#xff0c;数字型注入和字符型注入的基础上&#xff0c;进一步深入学习知识&#xf…...

Canvas修仙传·第三重天金丹境(上集) ——九转游戏开发心法之《灵蛇奇谭》

各位道友,历经前两重天的修炼,恭喜诸位突破"动画"与"交互"桎梏!今日我们将解锁Canvas修仙路上第一个质变境界——将代码炼化为游戏元神!(ノ◕ヮ◕)ノ*:・゚✧ 章前黑话词典 🔍 金丹境术语表: 游戏循环(Game Loop):驱动游戏逻辑的灵气泵状态机(Sta…...

Matplotlib基础知识总结

1、简介 安装使用pip install matplotlib命令即可&#xff1b; 2、基本绘图流程 3、pyplot基础语法 &#xff08;1&#xff09;创建画布与创建子图 figure语法说明&#xff1a;figure(numNone, figsizeNone, dpiNone, facecolorNone, edgecolorNone, frameonTrue)&#xff1…...

linux vim 撤销 回退操作

在Linux的vim编辑器中&#xff0c;撤销和回退操作是非常基本的&#xff0c;但它们可以通过不同的方式实现&#xff0c;具体取决于你想要的精确效果。下面是一些常用的方法&#xff1a; 1. 撤销&#xff08;Undo&#xff09; 单个撤销&#xff1a; 你可以通过按下u键来撤销上一…...

kubernetes Device Plugin原理与源码分析

一、背景与核心概念 1.1 Kubernetes设备管理演进之路 1.1.1 Extended Resource的局限性 在Kubernetes早期版本中&#xff0c;管理非标准硬件资源&#xff08;如GPU、FPGA&#xff09;主要依赖 Extended Resource&#xff08;扩展资源&#xff09; 机制&#xff0c;Extended …...

天佐.乾坤袋 基于抽屉式文件存储的NoSql数据库

天佐.乾坤袋 天佐.乾坤袋 简介 天佐.乾坤袋 基于抽屉式文件存储的NoSql数据库&#xff0c;可用于文件打包&#xff0c;数据整合&#xff0c;加密存放等多种用途。可以方便快捷的搭建和部署存储应用的系统。 传说: 弥勒所有&#xff0c;专做储物之用。拥有不可思议之力&#x…...

Spring Boot 消息队列(以RabbitMQ为例)

文章目录 RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装 Spring Boot 集成 RabbitMQ1. 创建 Spring Boot 项目2. 配置 RabbitMQ3. 定义消息队列和交换机4. 发送消息5. 接收消息6. 测试消息发送和接收 RabbitMQ 简介与安装 1. RabbitMQ 简介 RabbitMQ 是一个开源的消息…...

深度学习原理与Pytorch实战

深度学习原理与Pytorch实战 第2版 强化学习人工智能神经网络书籍 python动手学深度学习框架书 TransformerBERT图神经网络&#xff1a; 技术讲解 编辑推荐 1.基于PyTorch新版本&#xff0c;涵盖深度学习基础知识和前沿技术&#xff0c;由浅入深&#xff0c;通俗易懂&#xf…...

WPF-ReactiveUi

文章目录 依赖属性和命令的绑定弱绑定强绑定界面后台的cs文件强捆绑方式定义属性和命令第一种方法第二种方法第三种方法动态数据集合whenAny监听单个监听单个对象的多个属性监听多个对象对各属性whenAnyValue例程一例程二WhenAnyValue属性WhenAnyValue(x => x.SearchTerm)Th…...

和鲸科技携手四川气象,以 AI 的力量赋能四川气象一体化平台建设

气象领域与农业、能源、交通、环境科学等国计民生关键领域紧密相连&#xff0c;发挥着不可替代的重要作用。人工智能技术的迅猛发展&#xff0c;为气象领域突破困境带来了新的契机。AI 技术能够深度挖掘气象大数据中蕴含的复杂信息&#xff0c;助力人类更精准地把握自然规律&am…...

把GB型材库放入solidwork中点击库无法应

1、文件夹的位置要选择对&#xff0c;如下图&#xff1a; 2、文件夹一定要嵌套三层&#xff0c;如下图...

论文写作指南

一、论文的核心结构 1. 标题&#xff08;Title&#xff09; 要求&#xff1a; 简洁明确&#xff0c;体现核心研究内容&#xff08;一般不超过20字&#xff09;。 避免模糊词汇&#xff08;如“研究”“探讨”&#xff09;&#xff0c;可包含关键词。 示例&#xff1a; 《关…...

构建安全的Docker基础镜像:从最佳实践到自动化加固

引言 容器化技术的普及使得Docker镜像成为软件交付的核心载体,但镜像中的安全漏洞、敏感信息泄露和权限配置不当等问题可能引发严重风险。本文结合OWASP容器安全指南与一线运维经验,系统化讲解如何构建安全的Docker基础镜像,覆盖镜像构建、依赖管理、运行时防护全链路,并提…...

(动态规划 最大(连续)子数组和)leetcode 53

这道题和上个文章(动态规划 最长连续递增子序列&#xff09;leetcode 674有异曲同工之妙&#xff0c;本质是一样的&#xff0c;只是这个题更基础一点 递推公式中dp[i]max(dp[i],dp[i]dp[i-1])&#xff0c;可以发现&#xff0c;这里如果是背包问题&#xff0c;不取应该是max(dp…...

Python Cookbook-2.20 在 Python 的搜索路径中寻找文件

任务 一个大的 Python 应用程序包括了资源文件(比如 Glade 项目文件、SQL 模板和图片)以及 Python 包(Python package)。你想把所有这些相关文件和用到它们的 Python 包储存起来。 解决方案 可以在 Python 的 sys.path 中寻找文件或目录: import sys&#xff0c;os class E…...

3.对象生活的地方—Java环境搭建

1、你要养鱼&#xff0c;总得先有一个鱼塘吧。挖一个鱼塘来养鱼&#xff0c;你需要去做下面这些事情&#xff1a; 规划和设计&#xff1a;确定鱼塘的位置、大小和形状&#xff0c;绘制设计图。标记和测量&#xff1a;使用测量工具标记鱼塘的边界和深度。挖掘&#xff1a;使用挖…...

精品整理-2025 DeepSeek核心技术解析与实践资料合集(24份)

2025 DeepSeek核心技术解析与实践资料合集&#xff0c;共24份。 2025 DeepSeek 火爆背后的核心技术&#xff1a;知识蒸馏技术.pdf 2025 DeepSeek-R1详细解读&#xff1a;DeepSeek-R1-Zero和DeepSeek-R1分析.pdf 2025 DeepSeek-V3三个关键模块详细解读&#xff1a;MLAMoEMTP.pd…...

16.2 LangChain 表达式语言设计哲学:重新定义大模型应用开发范式

LangChain 表达式语言设计哲学:重新定义大模型应用开发范式 关键词:LCEL 设计哲学、声明式编程范式、生产级应用架构、流式处理优化、模块化组合 1. 核心设计目标全景图 mindmap root((LCEL设计目标)) 开发效率 声明式编程 类型提示系统 自动补全支持 工程可靠性 错…...

32位,算Cache地址

32位&#xff0c;算Cache地址...

Spring Boot 3.x 基于 Redis 实现邮箱验证码认证

文章目录 依赖配置开启 QQ 邮箱 SMTP 服务配置文件代码实现验证码服务邮件服务接口实现执行流程 依赖配置 <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr…...

微服务学习(2):实现SpringAMQP对RabbitMQ的消息收发

目录 SpringAMQP是什么 为什么采用SpringAMQP SpringAMQP应用 准备springBoot工程 实现消息发送 SpringAMQP是什么 Spring AMQP是Spring框架下用于简化AMQP&#xff08;高级消息队列协议&#xff09;应用开发的一套工具集&#xff0c;主要针对RabbitMQ等消息中间件的集成…...

c++中深拷贝和浅拷贝的联系和区别

在 C 编程里&#xff0c;深拷贝和浅拷贝是两种不同的对象复制方式&#xff0c;它们在实现方式、资源管理和适用场景等方面存在显著差异。下面为你详细介绍它们的区别。 1. 基本概念 浅拷贝&#xff1a;浅拷贝仅仅复制对象的成员变量值。对于基本数据类型&#xff08;如 int、d…...

mysql中事务的基本概念

事务的基本概念 一、事务的基本要素&#xff08;ACID&#xff09; 1. 原子性&#xff08;Atomicity&#xff09; 定义&#xff1a;事务中的所有操作要么全部成功&#xff0c;要么全部失败回滚&#xff0c;不允许部分完成。举例&#xff1a;A 向 B 转账&#xff0c;A 扣款和 …...

【密码学实战】Java 实现 SM2 国密算法(签名带id、验签及 C1C3C2 加密解密)

前言 SM2是中国国家密码管理局发布的椭圆曲线公钥密码算法标准&#xff08;GB/T 32918&#xff09;&#xff0c;属于国密算法体系。与RSA和ECDSA相比&#xff0c;SM2在相同安全强度下密钥更短、计算效率更高。本文将介绍如何在Java中实现SM2的密钥生成、数字签名、验签、加密及…...

如何修改安全帽/反光衣检测AI边缘计算智能分析网关V4的IP地址?

TSINGSEE青犀推出的智能分析网关V4&#xff0c;是一款集成了BM1684芯片的高性能AI边缘计算智能硬件。其内置的高性能8核ARM A53处理器&#xff0c;主频可高达2.3GHz&#xff0c;INT8峰值算力更是达到了惊人的17.6Tops。此外&#xff0c;该硬件还预装了近40种AI算法模型&#xf…...

LLM的演进趋势与未来展望:Toformer的革新之路

文章出处 题目&#xff1a;Restoring Images in Adverse Weather Conditions via Histogram Transformer 论文地址: https://arxiv.org/pdf/2407.10172 代码地址: https://github.com/sunshangquan/Histoformer 年份&#xff1a;2024 期刊&#xff1a;ECCV 背景 这篇文章…...

LabVIEW 无法播放 AVI 视频的编解码器解决方案

用户在 LabVIEW 中使用示例程序 Read AVI File.vi&#xff08;路径&#xff1a; &#x1f4cc; C:\Program Files (x86)\National Instruments\LabVIEW 2019\examples\Vision\Files\Read AVI File.vi&#xff09;时发现&#xff1a; ✅ LabVIEW 自带的 AVI 视频可正常播放 这是…...

Svelte vs Vue:前端框架的深度对比与应用场景分析

Svelte vs Vue&#xff1a;前端框架的深度对比与应用场景分析 1. 引言 前端开发领域的框架选择一直是开发者关注的重点。在现代 Web 开发中&#xff0c;Vue 和 Svelte 都是备受瞩目的框架&#xff0c;各自拥有不同的架构设计和适用场景。本文将从 核心架构、性能对比、开发体…...

如何在一台服务器上搭建 mongodb副本集1主2从节点

在一台服务器上搭建 MongoDB 副本集&#xff08;1 主节点 2 从节点&#xff09;可以通过运行多个 MongoDB 实例并使用不同端口和数据目录来实现。以下是详细步骤&#xff1a; 1. 准备工作 确保已安装 MongoDB。为每个实例创建独立的数据目录和日志文件。 2. 创建数据目录和…...

【湖北省计算机信息系统集成协会主办,多高校支持 | ACM出版,EI检索,往届已见刊检索】第二届边缘计算与并行、分布式计算国际学术会议(ECPDC 2025)

第二届边缘计算与并行、分布式计算国际学术会议&#xff08;ECPDC 2025&#xff09;将于2025年4月11日至13日在中国武汉盛大召开。本次会议旨在为边缘计算、并行计算及分布式计算领域的研究人员、学者和行业专家提供一个高水平的学术交流平台。 随着物联网、云计算和大数据技术…...

谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他

这是 ES 7.10 相较于 ES 6.8 新增内容的最后一篇&#xff0c;主要涉及算分方法和同义词加载的部分。 自定义算分&#xff1a;script_score 2.0 Elasticsearch 7.0 引入了新一代的函数分数功能&#xff0c;称为 script_score 查询。这一新功能提供了一种更简单、更灵活的方式来…...

大数据与金融科技:革新金融行业的动力引擎

大数据与金融科技&#xff1a;革新金融行业的动力引擎 在今天的金融行业&#xff0c;大数据与金融科技的结合正在以惊人的速度推动着金融服务的创新与变革。通过精准的数据分析与智能化决策&#xff0c;金融机构能够更高效地进行风险管理、客户服务、资产管理等一系列关键操作…...

企业jsapi_ticket,java举例

在企业微信开发中&#xff0c;使用 Java 获取 jsapi_ticket 并生成签名的步骤如下。以下是完整的 Java 示例代码。 1. 获取 jsapi_ticket 的流程 获取 access_token。 使用 access_token 获取 jsapi_ticket。 使用 jsapi_ticket 生成签名&#xff08;signature&#xff09;。…...

【Python】基础语法三

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解Python的函数、列表和数组。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff…...

leetcode_字典树 139. 单词拆分

139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 思路: 定义状态&#xff1a; 设dp[i]表…...

Easy Trans Spring Boot Starter ---Spring系列的字段翻译库

Easy Trans Spring Boot Starter 使用文档 1. 简介 easy-trans-spring-boot-starter 是一个基于 Spring Boot 的库&#xff0c;用于简化数据翻译和转换操作。它可以帮助你将数据库中的枚举值、状态码等转换为用户友好的文本&#xff0c;或者将一种数据格式转换为另一种格式。…...

算法-数据结构(图)-迪杰斯特拉最短逻辑算法( Dijkstra)

迪杰斯特拉算法&#xff08;Dijkstras Algorithm&#xff09; 是一种用于计算单源最短路径的经典算法&#xff0c;由荷兰计算机科学家 艾兹赫尔迪杰斯特拉&#xff08;Edsger W. Dijkstra&#xff09; 于1956年提出。它的主要目标是找到从图中的某个源节点到所有其他节点的最短…...

抖音生活服务加强探店内容治理,2024年达人违规率下降30%

发布 | 大力财经 2月27日&#xff0c;抖音生活服务发布《2024抖音生活服务消费者权益保护年度报告》&#xff08;以下简称“报告”&#xff09;。报告显示&#xff0c;过去一年&#xff0c;抖音生活服务针对消费者反感的虚假、夸张探店内容&#xff0c;开展了专项治理。通过一…...

跟着源码实现LevelDB(二)util/status.cc

概述 本小节实现了leveld的Status类&#xff0c;Status看起来是个简单的类&#xff0c;但是其中也包含了leveldb对极致的性能实现的巧妙设计 Status的内存管理 Status 只有一个成员变量 const char* state_; state[0…3] 表示长度&#xff0c;state[4] 1个字节 表示状态的枚…...