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

Java八股 深入理解Spring的AOP 面向切面编程 底层 保姆级教程 手写例子

目录

概念

AOP 术语

1. 连接点(Jointpoint):

2. 切入点(Pointcut):

3. 通知(Advice):

4. 方面/切面(Aspect):

5. 引入(inter-type declaration):

6. 目标对象(Target Object):

7. 织入(Weaving):

8. AOP代理(AOP Proxy):

通知类型:

1. 前置通知(Before advice):

2. 后置通知(After returning advice):

3. 异常通知(After throwing advice):

4. 最终通知(After (finally) advice):

5. 环绕通知(Around Advice):

AOP 术语 图解 重要

AOP 核心概念 小总结

Spring AOP和 AspectJ 是什么关系 区别

AOP 的配置方式

XML 形式

AspectJ 注解

最后想手写一个 AOP 例子结束

参考文章


概念

AOP 的目的是为了解耦 其次是简化开发

AOP 是 Spring 的核心 面向切面编程

他是一套规范

通过预编译方式和运行期间动态代理实现程序的统一维护

核心概念 就是 将分散在各个业务逻辑代码中的相同的代码通过横向切割的方式抽取到一个独立的模块中

AOP 术语

首先让我们从一些重要的AOP概念和术语开始。

这些术语不是Spring特有的

1. 连接点(Jointpoint):

表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点,在AOP中表示为在哪里干

2. 切入点(Pointcut):

选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为在哪里干的集合

3. 通知(Advice):

在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice),在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知;在AOP中表示为干什么

4. 方面/切面(Aspect):

横切关注点的模块化,比如上边提到的日志组件。可以认为是通知、引入和切入点的组合;在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为在哪干和干什么集合

5. 引入(inter-type declaration):

也称为内部类型声明,为已有的类添加额外新的字段或方法,Spring允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象), 在AOP中表示为干什么(引入什么)

6. 目标对象(Target Object):

需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为被通知对象;由于Spring AOP 通过代理模式实现,从而这个对象永远是被代理对象,在AOP中表示为对谁干

7. 织入(Weaving):

把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。在AOP中表示为怎么实现的

8. AOP代理(AOP Proxy):

AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。在AOP中表示为怎么实现的一种典型方式

通知类型:

1. 前置通知(Before advice):

在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。

2. 后置通知(After returning advice):

在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

3. 异常通知(After throwing advice):

在方法抛出异常退出时执行的通知。

4. 最终通知(After (finally) advice):

当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

5. 环绕通知(Around Advice):

包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

环绕通知是最常用的通知类型。和AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽可能简单的通知类型来实现需要的功能。例如,如果你只是需要一个方法的返回值来更新缓存,最好使用后置通知而不是环绕通知,尽管环绕通知也能完成同样的事情。用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。比如,你不需要在JoinPoint上调用用于环绕通知的proceed()方法,就不会有调用的问题。

AOP 术语 图解 重要

AOP 核心概念 小总结

AOP 的核心是连接点

连接点是我们需要关注的程序拓展点

可能是类初始化 方法执行 方法调用 字段调用 异常处理等

Spring 支持的连接点是方法执行点

切入点是一系列连接点的集合,Spring默认使用AspectJ语法,在AOP中抽象表示为可以进行操作的集合

之后就是通知

通知就是我们在连接点上执行的行为

连接点 切入点 通知组合在一起 就是一个切面

把切面映入到其他应用程序或者对象上,创建一个被通知的对象,这些就是织入,Spring 在运行时完成织入 ,在 AOP 中表示为怎么实现的,实现方式

Spring AOP和 AspectJ 是什么关系 区别

AspectJ 是一个更加强大的 AOP 框架 是一个 AOP 标准

如果只是简单的业务 可以使用 AOP

AOP 一个重要的原则就是无侵入性

AspectJ 重要的是 一般在编译期进行 即静态织入

在这个期间使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类。

动态织入的方式是在运行时动态将要增强的代码织入到目标类中,这样往往是通过动态代理技术完成的,如Java JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现),Spring AOP采用的就是基于运行时增强的代理技术。

Spring AOP更易用,AspectJ更强大

AOP 的配置方式

XML 形式

首先是业务逻辑

package aopByXml;// 目标类 核心业务
public class AopDemoServiceImpl {public void doMethod1() {System.out.println("aopByXml.AopDemoServiceImpl.doMethod1()");}public String doMethod2() {System.out.println("aopByXml.AopDemoServiceImpl.doMethod2()");return "hello world";}public String doMethod3() throws Exception {System.out.println("aopByXml.AopDemoServiceImpl.doMethod3()");throw new Exception("some exception");}
}

其次是切面类 我这边定义的方法都是通知

package aopByXml;import org.aspectj.lang.ProceedingJoinPoint;
// 切面类
public class LogAspect {/*** 环绕通知.** @param pjp pjp* @return obj* @throws Throwable exception*/public Object doAround(ProceedingJoinPoint pjp) throws Throwable {System.out.println("-----------------------");System.out.println("环绕通知: 进入方法");Object o = pjp.proceed();System.out.println("环绕通知: 退出方法");return o;}/*** 前置通知.*/public void doBefore() {System.out.println("前置通知");}/*** 后置通知.** @param result return val*/public void doAfterReturning(String result) {System.out.println("后置通知, 返回值: " + result);}/*** 异常通知.** @param e exception*/public void doAfterThrowing(Exception e) {System.out.println("异常通知, 异常: " + e.getMessage());}/*** 最终通知.*/public void doAfter() {System.out.println("最终通知");}
}

然后是 xml 配置文件 将切面(连接点+切入点+通知) 织入

<?xml version="1.0" encoding="UTF-8"?>
<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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
"><context:component-scan base-package="tech.pdai.springframework" /><aop:aspectj-autoproxy/><!-- 目标类 --><bean id="demoService" class="tech.pdai.springframework.service.AopDemoServiceImpl"><!-- configure properties of bean here as normal --></bean><!-- 切面 --><bean id="logAspect" class="tech.pdai.springframework.aspect.LogAspect"><!-- configure properties of aspect here as normal --></bean><aop:config><!-- 配置切面 --><aop:aspect ref="logAspect"><!-- 配置切入点 --><aop:pointcut id="pointCutMethod" expression="execution(* tech.pdai.springframework.service.*.*(..))"/><!-- 环绕通知 --><aop:around method="doAround" pointcut-ref="pointCutMethod"/><!-- 前置通知 --><aop:before method="doBefore" pointcut-ref="pointCutMethod"/><!-- 后置通知;returning属性:用于设置后置通知的第二个参数的名称,类型是Object --><aop:after-returning method="doAfterReturning" pointcut-ref="pointCutMethod" returning="result"/><!-- 异常通知:如果没有异常,将不会执行增强;throwing属性:用于设置通知第二个参数的的名称、类型--><aop:after-throwing method="doAfterThrowing" pointcut-ref="pointCutMethod" throwing="e"/><!-- 最终通知 --><aop:after method="doAfter" pointcut-ref="pointCutMethod"/></aop:aspect></aop:config><!-- more bean definitions for data access objects go here -->
</beans>

AspectJ 注解

XML 声明式存在不足 在配置文件里面写了太多繁琐的东西

下面是 AspectJ 提供的注解

Spring AOP的实现方式是动态织入,动态织入的方式是在运行时动态将要增强的代码织入到目标类中,这样往往是通过动态代理技术完成的;

如Java JDK的动态代理(Proxy,底层通过反射实现)

如 CGLIB的动态代理(底层通过继承实现)

Spring AOP采用的就是基于运行时增强的代理技术。

以 JDK 动态代理举例

接口 规则

package aopByAspectJJdk;// 定义接口
public interface IJdkProxyService {void doMethod1();String doMethod2();String doMethod3() throws Exception;
}

接口实现类 具体实现

package aopByAspectJJdk;// 接口实现类
public class JdkProxyDemoServiceImpl implements IJdkProxyService{@Overridepublic void doMethod1() {}@Overridepublic String doMethod2() {return "";}@Overridepublic String doMethod3() throws Exception {return "";}
}

动态代理类 织入

package aopByAspectJJdk;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;/*** @author pdai*/
@EnableAspectJAutoProxy
@Component
@Aspect
public class LogAspect {/*** define point cut.*/@Pointcut("execution(* tech.pdai.springframework.service.*.*(..))")private void pointCutMethod() {}/*** 环绕通知.** @param pjp pjp* @return obj* @throws Throwable exception*/@Around("pointCutMethod()")public Object doAround(ProceedingJoinPoint pjp) throws Throwable {System.out.println("-----------------------");System.out.println("环绕通知: 进入方法");Object o = pjp.proceed();System.out.println("环绕通知: 退出方法");return o;}/*** 前置通知.*/@Before("pointCutMethod()")public void doBefore() {System.out.println("前置通知");}/*** 后置通知.** @param result return val*/@AfterReturning(pointcut = "pointCutMethod()", returning = "result")public void doAfterReturning(String result) {System.out.println("后置通知, 返回值: " + result);}/*** 异常通知.** @param e exception*/@AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")public void doAfterThrowing(Exception e) {System.out.println("异常通知, 异常: " + e.getMessage());}/*** 最终通知.*/@After("pointCutMethod()")public void doAfter() {System.out.println("最终通知");}}

最后想手写一个 AOP 例子结束

加减乘除的接口

public interface Calculator {// 加法int add(int i, int j);// 减法int sub(int i, int j);// 乘法int mul(int i, int j);// 除法int div(int i, int j);
}

具体实现逻辑

public class CalculatorImpl implements Calculator {@Overridepublic int add(int i, int j) {int result = i + j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {int result = i - j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;System.out.println("方法内部 result = " + result);return result;}
}

切面


import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;@Component
@Aspect
public class LogAspect {@Pointcut("execution(public int com.dc.esb.CalculatorImpl.*(..))")public void pointCut() {}@Before("pointCut()")public void beforeMethod(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:" + methodName + ",参数:" + args);}@After("execution(public int com.dc.esb.CalculatorImpl.*(..))")public void afterMethod(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->后置通知,方法名:" + methodName);}@AfterReturning(value = "execution(public int com.dc.esb.CalculatorImpl.*(..))", returning = "result")public void afterReturningMethod(JoinPoint joinPoint, Object result) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->返回通知,方法名:" + methodName + ",结果:" + result);}@AfterThrowing(value = "execution(public int com.dc.esb.CalculatorImpl.*(..))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->异常通知,方法名:" + methodName + ",异常:" + ex);}@Around("execution(public int com.dc.esb.CalculatorImpl.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());Object result = null;try {System.out.println("环绕通知-->目标对象方法执行之前");//目标对象(连接点)方法的执行result = joinPoint.proceed();System.out.println("环绕通知-->目标对象方法返回值之后");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("环绕通知-->目标对象方法出现异常时");} finally {System.out.println("环绕通知-->目标对象方法执行完毕");}return result;}
}

参考文章

Spring基础 - Spring核心之面向切面编程(AOP) | Java 全栈知识体系

相关文章:

Java八股 深入理解Spring的AOP 面向切面编程 底层 保姆级教程 手写例子

目录 概念 AOP 术语 1. 连接点&#xff08;Jointpoint&#xff09;&#xff1a; 2. 切入点&#xff08;Pointcut&#xff09;&#xff1a; 3. 通知&#xff08;Advice&#xff09;&#xff1a; 4. 方面/切面&#xff08;Aspect&#xff09;&#xff1a; 5. 引入&#xff…...

macOS安全隐私最佳实践分析

1. 引言 随着数字世界的不断扩展&#xff0c;个人和组织面临的安全与隐私威胁也日益增加。作为专业的安全合规与隐私保护研究团队&#xff0c;Kaamel 对 macOS 系统的安全隐私现状进行了全面分析&#xff0c;并提出了一系列最佳实践建议&#xff0c;旨在帮助用户更好地保护自己…...

WeakSet:JavaScript 中容易被忽视的“弱集合”

目录 WeakSet 详解 基本概念 创建 WeakSet WeakSet 的主要方法 WeakSet 的特性 WeakSet 的使用场景 1. 避免内存泄漏&#xff08;DOM 元素管理&#xff09; 2. 临时缓存系统 3. 私有属性模拟 4. 防止循环引用 与其他数据结构的对比 1. WeakSet 没有实例属性 2. We…...

Discuz!+DeepSeek:传统论坛的智能化蜕变之路

在数字化浪潮中&#xff0c;社区论坛作为互联网早期的产物&#xff0c;面临着功能单一、用户体验滞后的发展瓶颈。虎跃办公&#xff08;https://www.huyueapp.com&#xff09;通过Discuz!搭建的网址导航网站&#xff0c;在集成DeepSeek的AI能力后&#xff0c;成功实现了从工具导…...

vs2017中,将CMake构建目录设置在项目目录下

修改CMake构建目录位置 在Visual Studio 2017中&#xff0c;可以通过以下方法将CMake构建目录设置在项目目录下&#xff1a; 修改CMakeSettings.json文件‌&#xff1a; 在VS中生成CMakeSettings.json文件&#xff08;通过点击编译平台按钮如x64-Debug或x64-Release&#xf…...

跨平台.NET 版本 使用率排名

截至2025年4月&#xff0c;跨平台.NET版本的安装使用率排名主要基于版本支持状态、性能优化和企业迁移趋势。以下是结合微软官方政策、行业动态及开发者行为分析的综合结论&#xff1a; 1. .NET 8 (LTS) 占据主导地位 支持周期&#xff1a;作为2023年11月发布的长期支持&…...

基于无障碍跳过广告-基于节点跳过广告

2025-04-22 一些广告的关闭是叉图标&#xff0c;获取到的信息也没什么特征&#xff0c;这种广告怎么跳过 用autojs无障碍的节点定位ui控件位置&#xff0c;点击...

STM32提高篇: WIFI通讯

STM32提高篇: WIFI通讯 一.WIFI通讯介绍1.WiFi的频段5G和2.4G2.WiFi的信道二.ESP32固件烧录及驱动1.一个AT指令响应的完成2.测试其他指令三.Wifi功能初始化和TCP通讯四.volatile关键字一.WIFI通讯介绍 Wi-Fi,又称“无线网路”,是Wi-Fi联盟的商标,一个基于IEEE 802.11标准的…...

资本怪兽贝莱德投资数据分析报告-独家

贝莱德概述 贝莱德集团是全球最大的资产管理公司&#xff0c;其管理的资产规模达到了11.6万亿美元(约合人民币84.18万亿元)&#xff0c;这个数字相当于中国2024年GDP的62%。贝莱德通过收购李嘉诚旗下的43个全球港口资产&#xff0c;将在全球运营约100个港口。此外&#xff0c;…...

操作系统-用户级-内核级线程

一、先明确几个基本概念&#xff1a; 用户级线程&#xff08;ULT&#xff09;&#xff1a; 完全由用户空间的线程库&#xff08;如 pthread 或 green threads&#xff09;管理。 操作系统内核对此一无所知。 切换线程时&#xff0c;不需要进入内核&#xff0c;效率高&#xf…...

【深度学习】LoRA:低秩适应性微调技术详解

LoRA&#xff1a;低秩适应性微调技术详解 文章目录 LoRA&#xff1a;低秩适应性微调技术详解1. 引言2. LoRA原理解析2.1 核心思想2.2 数学表达 3. LoRA实现细节3.1 适用层选择3.2 缩放因子3.3 初始化策略 4. 代码实现示例5. LoRA在实际应用中的优势5.1 内存效率5.2 训练速度5.3…...

研发效率破局之道阅读总结(3)工程优化

研发效率破局之道阅读总结(3)工程优化 Author: Once Day Date: 2025年4月22日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 程序的艺术_Once-Day…...

树莓派超全系列教程文档--(40)树莓派config.txt旧版GPIO控制、超频及条件过滤器

树莓派config.txt旧版GPIO控制、超频及条件过滤器 传统GPIO控制enable_jtag_gpio 传统超频选项超频never_over_voltagedisable_auto_turbo 遗留条件过滤器The [HDMI:*] 过滤器 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 传统GPIO控制 &…...

网络基础概念(下)

网络基础概念&#xff08;上&#xff09;https://blog.csdn.net/Small_entreprene/article/details/147261091?sharetypeblogdetail&sharerId147261091&sharereferPC&sharesourceSmall_entreprene&sharefrommp_from_link 网络传输的基本流程 局域网网络传输流…...

DES、3DES、SM4 加密算法简介

1. DES&#xff08;Data Encryption Standard&#xff09; 设计时间&#xff1a;1975 年&#xff08;IBM 开发&#xff0c;1977 年被 NIST 采纳为美国联邦标准&#xff09;。 密钥长度&#xff1a;64 位&#xff08;实际有效 56 位 8 位校验&#xff09;。 分组长度&#xf…...

如何在 Ansys Icepak AEDT 中设置多个流程以加快仿真速度?

您将学习如何进行正确的设置&#xff0c;以通过增加进程数量来加快仿真速度。 Ansys Icepak AEDT 需要与 Icepak Classic 不同的设置。 要设置要在 Ansys Icepak AEDT 中使用的进程数&#xff0c;您需要按照以下步骤作&#xff1a; 首先&#xff0c;转到“工具 - >选项 - …...

【MCP Node.js SDK 全栈进阶指南】初级篇(2):MCP基础服务器开发

引言 在上一篇文章中,我们详细介绍了MCP开发环境的搭建。本文作为MCP TypeScript-SDK系列的第二篇,将深入探讨MCP基础服务器开发的核心内容,包括服务器创建与生命周期管理、McpServer与Server的区别与选择、各种配置选项的详解,以及基本启动与调试技巧。通过本文学习,你将…...

客户端 AI 与服务器端 AI 的深度比较及实践建议?

1. 性能与延迟 ​​客户端AI&#xff08;In-Browser AI&#xff09;​​&#xff1a; // 使用TensorFlow.js在浏览器中进行图像分类 const model await tf.loadLayersModel(local-model/model.json);// 实时摄像头处理 const video document.getElementById(webcam); const…...

【(保姆级教程)Ubuntu24.10下部署Dify】

目录 一、下载Ubuntu二、安装Ubuntu三、在 Ubuntu 上安装 Docker Engine1、设置Docker的apt仓库2、安装 Docker 包 四、在 Ubuntu 上安装 Docker Desktop1、先决条件2、下载最新 DEB 包3、安装软件包4、启动 Docker Desktop5、检查版本 五、克隆 Dify 代码仓库六、启动 Dify1、…...

计算机组成原理---总线系统的详细概述

1.数据传输的两个方式 串行传输和并行传输&#xff1a;串行传输和并行传输 串行&#xff1a;适合的就是传输的距离比较远&#xff0c;这个对应的成本也是比较低的&#xff1b; 并行&#xff1a;传输的效率很高&#xff0c;因为分成了不同的线路&#xff0c;这个适合的就是短距离…...

C++静态与动态联编区别解析

在 C++ 中,静态联编(Static Binding)和动态联编(Dynamic Binding)是两种不同的函数调用绑定机制,核心区别在于确定函数调用的时机和多态性的支持。以下是详细解释: 1. 静态联编(Static Binding) 定义:在编译阶段确定函数调用与具体实现的关系。特点: 由编译器直接确…...

Linux 一些常用的命令记录

常见命令如下 查询内容 find / -name 例如&#xff1a;查找 libstdc.so* find / -name "libstdc.so*" 查询运行环境&#xff1a;/lib64/libstdc.so.6 内容是可以修改为其他的 strings /lib64/libstdc.so.6 | grep CXXABI创建软连接&#xff08;创建超链接&…...

面试题-链表(1)

1.移除链表元素&#xff1a; 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 删除一个链表中的相同元素。 我这里用的方法只需要将链表遍历一次&#xff0c;就可以删除所有节点。 前后指针法: public ListNode removeElements(ListNode head, int val) { //先判…...

【云馨AI-大模型】Dify 1.2.0:极速集成 SearXNG,畅享智能联网搜索新境界,一键脚本轻松部署SearXNG

SearXNG部署目录创建一键脚本SearXNG访问 Dify SearXNG插件安装SearXNG 插件安装进行授权工作流中进行验证工作流测试 SearXNG部署 目录创建 mkdir -p /data/yunxinai && cd /data/yunxinai 一键脚本 git clone https://gitcode.com/yunxinai/rag-sh.git 一键执行脚…...

Python 设计模式:访问者模式

1. 什么是访问者模式&#xff1f; 访问者模式是一种行为设计模式&#xff0c;它允许你在不改变对象结构的前提下&#xff0c;定义新的操作。通过将操作封装在访问者对象中&#xff0c;访问者模式使得你可以在不修改元素类的情况下&#xff0c;向元素类添加新的功能。 访问者模…...

dify工作流之text-2-e-sql,大模型写sql并执行

市面上有太多的text-to-sql工具&#xff0c;但是我这次突发灵感&#xff0c;为什么不做一个可以执行sql得text2sql呢。 dify的安装我不再赘述&#xff0c;我采用的是win10本地docker部署的方式。 mysql的安装也不再介绍&#xff0c;如有需要还请移步其他博主。 1.dify创建工…...

Neo4j 可观测性最佳实践

Neo4j 介绍 Neo4j 是一款领先的图数据库管理系统&#xff0c;采用图数据模型来表示和存储数据。它以节点、关系和属性的形式组织数据&#xff0c;节点代表实体&#xff0c;关系表示节点间的连接&#xff0c;属性则为节点和关系附加信息。Neo4j 使用 Cypher 查询语言&#xff0…...

【随手记】jupyter notebook绘制交互式图像

在 Jupyter Notebook 中 魔法命令特点%matplotlib notebook图形是交互式的&#xff0c;可缩放、旋转&#xff08;适合 3D 图&#xff09;%matplotlib inline图像静态显示&#xff0c;简单快速&#xff0c;适用于大多数2D图绘制 在 %matplotlib notebook 的 3D 图中&#xff0c…...

[大模型]AI Agent入门01——AI Agent概念梳理

什么是 Agent&#xff08;智能体&#xff09; 定义 Agent 是并能够感知环境&#xff0c;同时可以自主采取行动以实现特定目标的实体。 Agent&#xff08;代理&#xff09;是计算机科学中的一个概念&#xff0c;​​指一种置于某种环境中&#xff0c;能够感知环境中的信息并自…...

【锂电池剩余寿命预测】BiLSTM双向长短期记忆神经网络锂电池剩余寿命预测(Matlab源码)

目录 效果一览程序获取程序内容代码分享研究内容BiLSTM双向长短期记忆神经网络锂电池剩余寿命预测摘要关键词1. 引言1.1 研究背景1.2 研究现状与问题1.3 研究目的与意义2. 文献综述2.1 锂电池剩余寿命预测理论基础2.2 传统预测方法概述2.3 基于深度学习的预测方法进展3. BiLSTM…...

基于机器学习的房租影响因素分析系统

基于机器学习的房租影响因素分析系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】数据可视化及预测分析的完整流程文档 【技术栈】 ①&#xff1a;系统环境&#xff1a;Python 3.8, Django 4.2 ②&#xff1a;开发环境&#…...

【c++深入系列】:万字string详解(附有sso优化版本的string模拟实现源码)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 当你想放弃时&#xff0c;想想为什么当初坚持走到了这里 ★★★ 本文前置知识&#xff1a; 类和对象&#xff08;上&#xff09; 类和对…...

黑马点评redis改 part 4

Redis消息队列实现异步秒杀 一些额外话语&#xff1a;过来人提醒下&#xff0c;不要用stream&#xff0c;可以跳过不看&#xff0c;用专业的消息队列中间件&#xff0c;同时准备好消息队列的八股&#xff0c;否则简陋的stream很容易被问死。 异步持久化还存在消息丢失、消息重复…...

【Python Web开发】01-Socket网络编程01

文章目录 1.套接字(Socket)1.1 概念1.2 类型1.3 使用步骤 Python 的网络编程主要用于让不同的计算机或者程序之间进行数据交换和通信&#xff0c;就好像人与人之间打电话、发消息一样。 下面从几个关键方面通俗易懂地介绍一下&#xff1a; 1.套接字(Socket) 在 Python 网络编…...

『不废话』之Python管理工具uv快速入门

在『不废话』之大模型推理超参数解释『不废话』之动手学MCP 中提到了uv&#xff0c;很多朋友都说没用过&#xff0c;咨询有什么优势&#xff1f; 通常Python新手都会使用conda、miniconda来管理Python环境&#xff0c;稍微高阶水平的会使用pyenv、poetry、virtualenv等工具来管…...

2025年中国高端家电品牌市场分析:海尔Haier、美的Midea、格力GREE三大本土品牌合计占据70%市场份额

一、市场现状&#xff1a;需求升级与结构性增长并存 2024年&#xff0c;中国高端家电市场在复杂的经济环境中展现出“逆势增长”的韧性。尽管全球经济增速放缓&#xff0c;国内家电零售额同比微降0.4%至6957亿元&#xff0c;但高端家电却成为拉动市场的重要引擎。这一现象的背…...

【漫话机器学习系列】217.监督式深度学习的核心法则(Supervised Deep Learning Rule Of Thumb)

监督式深度学习的核心法则&#xff1a;你需要多少数据&#xff1f; 原图作者&#xff1a;Chris Albon 在进行深度学习项目时&#xff0c;我们常常面临一个核心问题&#xff1a;我到底需要多少训练数据&#xff1f;这是许多初学者甚至资深工程师都会困惑的问题。图中给出了一个非…...

OpenCV --- 图像预处理(六)

OpenCV — 图像预处理&#xff08;六&#xff09; 文章目录 OpenCV --- 图像预处理&#xff08;六&#xff09;十四&#xff0c;图像边缘检测14.1 高斯滤波14.2 计算图像的梯度与方向14.3 非极大值抑制14.4 双阈值筛选14.5 API和使用 十五&#xff0c;绘制图像轮廓15.1 什么是轮…...

WebRTC服务器Coturn服务器的管理平台功能

1、概述 开源的webrtc服务器提供管理平台功能&#xff0c;用户可以通过web页面进行访问配置coturn服务器&#xff0c;主要包括管理平台功能和telnet的管理功能&#xff0c;coturn相当于telnet服务器&#xff0c;可能通过配置来开启这两个功能&#xff0c;方便查看coturn服务器…...

华为网路设备学习-19 路由策略

一、 二、 注意&#xff1a; 当该节点匹配模式为permit下时&#xff0c;参考if else 当该节点匹配模式为deny下时&#xff1a; 1、该节点中的apply子语句不会执行。 2、如果满足所有判断&#xff08;if-match&#xff09;条件时&#xff0c;拒绝该节点并跳出&#xff08;即不…...

理解RAG第六部分:有效的检索优化

在RAG系统中&#xff0c;识别相关上下文的检索器组件的性能与语言模型在生成有效响应方面的性能同样重要&#xff0c;甚至更为重要。因此&#xff0c;一些改进RAG系统的努力将重点放在优化检索过程上。 从检索方面提高RAG系统性能的一些常见方法。通过实施高级检索技术&#x…...

DOCA介绍

本文分为两个部分&#xff1a; DOCA及BlueField介绍如何运行DOCA应用&#xff0c;这里以DNS_Filter为例子做大致介绍。 DOCA及BlueField介绍&#xff1a; 现代企业数据中心是软件定义的、完全可编程的基础设施&#xff0c;旨在服务于跨云、核心和边缘环境的高度分布式应用工作…...

Hadoop----高可用搭建

目录标题 **什么是高可用&#xff1f;****⭐搭建的步骤**一.jdk**安装配置**- **要点**: 二.zookeeper**集群配置**- **要点** 三.Hadoop高可用的搭建- **要点**①环境变量的配置②配置文件的修改 ③内容分发④集群任务的初次启动 什么是高可用&#xff1f; 通过冗余设计 自动…...

2023蓝帽杯初赛内存取证-1

获取关于内存镜像文件的基本信息&#xff1a; vol.py -f memdump.mem imageinfo 得知Image local date and time : 2023-06-21 01:02:27 0800 Image local date and time是本地时区&#xff08;中国——东八区&#xff09; 答案&#xff1a;2023-06-21 01:02:27...

算法之回溯法

回溯法 回溯法定义与概念核心思想回溯法的一般框架伪代码表示C语言实现框架 回溯法的优化技巧剪枝策略实现剪枝的C语言示例记忆化搜索 案例分析N皇后问题子集和问题全排列问题寻路问题 回溯法的可视化理解决策树状态空间树回溯过程 回溯法与其他算法的比较回溯法与动态规划的区…...

Linux 内核中 cgroup(控制组) 作用是什么?

cgroup&#xff08;Control Groups&#xff09; 是 Linux 内核提供的一种机制&#xff0c;用于对 进程&#xff08;或线程&#xff09;组 进行资源限制、优先级分配、统计监控和任务控制。通过将进程分组管理&#xff0c;可以实现对 CPU、内存、磁盘 I/O、网络等系统资源的精细…...

Relay IR的核心数据结构

在 Apache TVM 的 Relay IR 中&#xff0c;基础节点&#xff08;Var、Const、Call、Function 和 Expr&#xff09;是构建计算图的核心数据结构。以下是对它们的详细解析&#xff0c;包括定义、作用、内部组成及相互关系&#xff1a; 1. Expr&#xff08;表达式基类&#xff09;…...

【MCP Node.js SDK 全栈进阶指南】初级篇(4):MCP工具开发基础

在MCP(模型上下文协议)的生态系统中,工具(Tools)是一种强大的扩展机制,允许AI模型执行各种操作并获取结果。本文将深入探讨MCP TypeScript-SDK中的工具开发基础,包括工具定义与参数验证、Zod模式详解与高级用法、异步工具处理与错误管理以及工具调用与结果格式化。通过学…...

3Blue1Brown/videos - 数学视频生成代码库

本文翻译整理自&#xff1a;https://github.com/3b1b/videos 文章目录 一、关于本项目相关链接资源关键功能特性 二、注意事项三、工作流1、核心原理2、Sublime 专用配置 四、快捷键功能说明 一、关于本项目 本项目包含用于生成 3Blue1Brown 数学解说视频的代码。 相关链接资源…...

vue3 + element-plus中el-drawer抽屉滚动条回到顶部

el-drawer抽屉滚动条回到顶部 <script setup lang"ts" name"PerformanceLogQuery"> import { ref, nextTick } from "vue"; ...... // 详情 import { performanceLogQueryByIdService } from "/api/performanceLog"; const onD…...