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

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…...

保生产 促安全 迎国庆

2021年的国庆节已经临近&#xff0c;与此同时陕化也迎来了祖国母亲的第七十二个生日&#xff0c;在这个普天同庆的日子里&#xff0c;陕化BDO分厂丁二醇单元化工一组的员工依然会坚守在工作的一线&#xff0c;为“保生产 促安全 迎国庆”护航掌舵&#xff0c;化工一组一直秉持着…...

【Flutter DevTools】性能优化的瑞士军刀

一、性能分析&#xff1a;帧率与资源监控 1.1 帧率监控&#xff08;Performance面板&#xff09; 通过Performance面板可实时捕获应用的渲染流水线数据。开发者点击"Record"按钮后&#xff0c;DevTools会以时间轴形式展示每一帧的构建、布局、绘制耗时。当帧率低于…...

C++std::map

1. 概述​​ ​​定义​​&#xff1a;std::map 是C标准模板库&#xff08;STL&#xff09;中的关联容器&#xff0c;以键值对&#xff08;key-value pairs&#xff09;形式存储元素&#xff0c;支持快速查找和有序访问。 ​​- 头文件​​&#xff1a;#include ​​底层实现​…...

dispaly: inline-flex 和 display: flex 的区别

display: inline-flex 和 display: flex 都是 CSS 中用于创建弹性盒子布局&#xff08;Flexbox&#xff09;的属性值&#xff0c;但它们之间有一些关键的区别&#xff0c;主要体现在元素如何在页面上被渲染和它们对周围元素的影响。 主要区别 1&#xff0c;块级 vs 行内块级 d…...

性能比拼: Elixir vs Go(第二轮)

本内容是对知名性能评测博主 Anton Putra Elixir vs Go (Golang) Performance Benchmark (Round 2) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 这是第二轮关于 Elixir 和 Go 的对比测试。我收到了一份来自 Elixir 创作者的 Pull Request &#xff0c;并且我认为…...

鸿蒙NEXT开发键值型数据工具类(ArkTs)

import { AppUtil } from ./AppUtil; import { distributedKVStore } from kit.ArkData; import { BusinessError } from kit.BasicServicesKit;/*** 键值型数据库工具类* author CSDN-鸿蒙布道师* since 2025/04/18*/ export class KvUtil {private static kvStore: distribut…...

【数字图像处理】立体视觉信息提取

双目立体视觉原理 设一个为参考平面&#xff0c;一个为目标平面。增加了一个摄像头后&#xff0c;P与Q在目标面T上有分别的成像点 双目立体视觉&#xff1a;从两个不同的位置观察同一物体&#xff0c;用三角测量原理计算摄像机到该物体的距离的 方法 原理&#xff1a;三角测量…...

Linux ssh免密登陆设置

使用 ssh-copy-id 命令来设置 SSH 免密登录&#xff0c;并确保所有相关文件和目录权限正确设置&#xff0c;可以按照以下步骤进行&#xff1a; 步骤 1&#xff1a;在源服务器&#xff08;198.120.1.109&#xff09;生成 SSH 密钥对 如果还没有生成 SSH 密钥对&#xff0c;首先…...

CentOS7执行yum命令报错 Could not retrieve mirrorlist http://mirrorlist.centos.org

CentOS7执行yum命令报错 引更新yum源备份原有源创建新的源文件清理并重建缓存 引 CentOS 7 系统无法连接到 CentOS 的官方镜像站点。这通常是由于网络问题或 CentOS 7 已停止维护导致的&#xff08;2024年6月30日后 CentOS 7 已进入 EOL&#xff09; 报错明细&#xff1a; 已…...

【漏洞复现】Struts2系列

【漏洞复现】Struts2系列 1. 了解Struts21. Struts2 S2-061 RCE &#xff08;CVE-2020-17530&#xff09;1. 漏洞描述2. 影响版本3. 复现过程 1. 了解Struts2 Apache Struts2是一个基于MVC设计模式的Web应用框架&#xff0c;会对某些标签属性&#xff08;比如 id&#xff09;的…...

Sentinel源码—5.FlowSlot借鉴Guava的限流算法二

大纲 1.Guava提供的RateLimiter限流使用示例 2.Guava提供的RateLimiter简介与设计 3.继承RateLimiter的SmoothBursty源码 4.继承RateLimiter的SmoothWarmingUp源码 3.继承RateLimiter的SmoothBursty源码 (1)SmoothBursty的初始化流程 (2)SmoothBursty的初始化完成后的变量…...

下载electron 22.3.27 源码错误集锦

下载步骤同 electron源码下载及编译_electron源码编译-CSDN博客 问题1 从github 下载 dugite超时&#xff0c;原因没有找到 Validation failed. Expected 8ea2d0d3c9d9e4615069913207371ffe892dc10fb93975972f2f6e668f2e3b3a but got e3b0c44298fc1c149afbf4c8996fb92427ae41e…...

安卓的桌面 launcher是什么

安卓的桌面Launcher是一种安卓应用程序&#xff0c;它主要负责管理和展示手机主屏幕的界面以及相关功能&#xff0c;为用户提供与设备交互的主要入口。以下是其详细介绍&#xff1a; 功能 主屏幕管理&#xff1a;用户可以在主屏幕上添加、删除和排列各种应用程序图标、小部件…...

基础数学知识-线性代数

1. 矩阵相乘 c i j = a i k ∗ b k j c_{ij} = a_{ik} * b_{kj} cij​=aik​∗bkj​ 1. 范数 1. 向量的范数 任意一组向量设为 x ⃗ = ( x 1 , x 2 , . . . , x N ) \vec{x}=(x_1,x_2,...,x_N) x =(x1​,x2​,...,xN​) 如下: 向量的1范数: 向量的各个元素的绝对值之和∥ …...

kubeadm极速部署Kubernetes 1.26.X 版本集群

1.1 Kubernetes 1.26版本集群部署环境准备 1.1.1 主机操作系统说明 序号操作系统及版本备注1CentOS7u9 1.1.2 主机硬件配置说明 需求CPU内存硬盘角色主机名值4C8G100GBmastermaster01值4C8G100GBworker(node)node01值4C8G100GBworker(node)node02 1.1.3 主机配置 1.1.3.1…...

重构未来智能:Anthropic 解码Agent设计哲学三重奏

第一章 智能体进化论&#xff1a;从工具到自主体的认知跃迁 1.1 LLM应用范式演进图谱 阶段技术形态应用特征代表场景初级阶段单功能模型硬编码规则执行文本摘要/分类进阶阶段工作流编排多模型协同调度跨语言翻译流水线高级阶段自主智能体动态决策交互编程调试/客服对话 1.1.…...

互联网大厂Java面试:微服务与分布式系统挑战

互联网大厂Java面试&#xff1a;微服务与分布式系统挑战 在互联网的大潮中&#xff0c;无数程序员怀揣着梦想&#xff0c;希望能在一线大厂找到自己的位置。今天的故事主角是马飞机&#xff0c;一位充满幽默感但技术略显水货的程序员。他来到了一家知名互联网公司参加Java开发…...

Gradle与Idea整合

文章目录 1. Groovy 简介2. Groovy 安装[非必须]3. 在idea中创建java工程 1. Groovy 简介 在某种程度上&#xff0c;Groovy可以被视为Java的一种脚本化改良版,Groovy也是运行在JVM上&#xff0c;它可以很好地与Java代码及其相关库进行交互操作。它是一种成熟的面向对象编程语言…...

基于springboot+vue的校园二手物品交易平台

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…...

PoCL环境搭建

PoCL环境搭建 **一.关键功能与优势****二.设计目的****三.测试步骤**1.创建容器2.安装依赖3.编译安装pocl4.运行OpenCL测试程序 Portable Computing Language (PoCL) 简介 Portable Computing Language (PoCL) 是一个开源的、符合标准的异构计算框架&#xff0c;旨在为 OpenCL…...

【前端Skill】点击目标元素定位跳转IDE中的源代码

参考&#xff1a;https://juejin.cn/post/7326002010084311079 快手开源项目&#xff1a; https://github.com/zh-lx/code-inspector 目前在umi项目中用到 记录一下umi项目中如何使用 安装 npm i code-inspector-plugin -D --registryhttps://registry.npmmirror.com/ 配…...

OpenCV图像上加数字水印示例

OpenCV计算机视觉开发实践&#xff1a;基于Qt C - 商品搜索 - 京东 14.1 基本概念 当今&#xff0c;生成式人工智能&#xff08;Artificial Intelligence Generated Content&#xff0c;AIGC&#xff09;的火爆引燃了数字水印&#xff0c;说实话数字水印并不是一项新的技术&…...

Python爬虫从入门到实战详细版教程Char01:爬虫基础与核心技术

1.1 什么是网络爬虫? 1.1.1 定义与分类 网络爬虫:互联网世界的“信息捕手” 网络爬虫(Web Crawler),又称网络蜘蛛或网络机器人,是一种通过预设规则自动访问网页、提取数据的程序系统。从技术视角看,其核心任务是通过模拟浏览器行为向目标服务器发起请求,解析网页内容…...

使用blob文件流

1.后端 GetMapping(value "/static/**")public void view(HttpServletRequest request, HttpServletResponse response) {// ISO-8859-1 > UTF-8 进行编码转换String imgPath extractPathFromPattern(request);if(oConvertUtils.isEmpty(imgPath) || imgPath&q…...

Day-1 漏洞攻击实战

实训任务1 漏洞攻击实战一 使用 御剑 得到网站后台地址 数据库登录与日志配置​​ 使用默认密码 root:root 登录phpMyAdmin&#xff0c;执行 SHOW VARIABLES LIKE general% 查看日志状态。 开启日志功能&#xff1a;set global general_log "ON";&#xff08;配图&…...

AOSP Android14 Launcher3——RecentsView最近任务数据加载

最近任务是Launcher中的一个重要的功能&#xff0c;显示用户最近使用的应用&#xff0c;并可以快速切换到其中的应用&#xff1b;用户可以通过底部上滑停顿进入最近任务&#xff0c;也可以在第三方应用底部上滑进最近任务。 这两种场景之前的博客也介绍过&#xff0c;本文就不…...

基于深度学习的校园食堂菜品智能结算系统

校园食堂菜品智能结算系统说明文档 1. 系统概述 本系统是一款基于YOLO深度学习算法的校园食堂菜品智能结算平台&#xff0c;旨在通过计算机视觉技术实现食堂菜品的自动识别与结算&#xff0c;提高结算效率&#xff0c;减少人工成本&#xff0c;优化用户体验。系统采用PyQt5框…...

【UniApp】Vue2 scss 预编译器默认已由 node-sass 更换为 dart-sass

从 HBuilderX 4.56 &#xff0c;vue2 项目也将默认使用 dart-sass 预编译器。 vue2开发者sass预处理注意&#xff1a; sass的预处理器&#xff0c;早年使用node-sass&#xff0c;也就是vue2最初默认的编译器。 sass官方推出了dart-sass来替代。node-sass已经停维很久了。 另…...

AI 硬件定制:开启智能新时代的钥匙

AI 硬件定制:开启智能新时代的钥匙 在科技飞速发展的当下,人工智能(AI)已不再是遥不可及的概念,它正以惊人的速度融入我们生活的方方面面。从智能手机中的语音助手,到工厂里的自动化生产线,AI 的身影无处不在。而在这股 AI 浪潮中,AI 硬件定制正逐渐崭露头角,成为推动…...