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

【Spring】(四)Bean 的作用域和生命周期

文章目录

  • 前言
  • 一、Bean 的作用域
    • 1.1 被修改的 Bean 案例
    • 1.2 作用域的定义
    • 1.3 Bean 的六种作用域
    • 1.4 Bean 作用域的设置
  • 二、Spring 的执行流程 和 Bean 的生命周期
    • 2.1 Spring 的执行流程
    • 2.2 Bean 的生命周期
    • 2.3 Bean 生命周期的演示


前言

Bean 是 Spring 框架中的一个核心概念,它是指由 Spring 容器管理的对象实例。在使用 Spring 进行开发时,我们通常会定义各种各样的 Bean,用于承载应用程序的不同功能和组件。然而,很多开发者可能只关注了 Bean 的定义和使用方式,而忽略了 Bean 的作用域和生命周期,这两者对于一个应用程序的性能、稳定性和可维护性都至关重要。

在本文中,我将深入讨论 Bean 的作用域和生命周期,并解释它们对于 Spring 应用程序的影响。我会尽量用简单明了的语言来阐述这些概念,以便读者能够轻松理解和应用到自己的开发实践中。

一、Bean 的作用域

初次看到 Bean 的作用域这个名词,可能会令我们一头雾水,但是没关系,接下来的一个简单案例将会告诉我们什么是 Bean 的作用域。

1.1 被修改的 Bean 案例

现在有一个公共的 Bean对象,可以供 A 和 B 两个用户使用,但是 A 在使用这个 Bean 对象的时候却悄悄的对这个 Bean 的数据进行了修改,那么会不会导致 B 用户在使用这个 Bean 对象的时候发生预期之外的结果呢?

创建一个 UserBean 的类,它的作用是通过 @Bean 注解的方式将 User 对象存储到 Spring 容器中,其中 User 包含一个 idname 属性:

@Component
public class UserBeans {@Beanpublic User getUser(){User user = new User();user.setId(123);user.setName("张三");return user;}
}

然后创建一个 UserController1 类,通过 @Controller 注解将其存储到 Spring 容器中,然后使用属性注解获取 Spring 容器中的 Bean 对象。另外创建一个 printUser 方法,里面创建一个临时引用 myUser 指向 Bean 对象,然后对这个 Bean 的数据进行修改:

@Controller
public class UserController1 {@Autowiredprivate User user;public void printUser(){System.out.println("user: " +  user);User myUser = user;myUser.setName("李四");System.out.println("myUser: " + myUser);System.out.println("user: " +  user);}
}

另外再创建一个 UserController2,同样使用 @Controller 注解将其存储到 Spring 容器中,然后使用属性注解获取 Spring 容器中的 Bean 对象。另外创建一个 printUser 方法,只打印获取到的 Bean 对象:

@Controller
public class UserController2 {@Resourceprivate User user;public void printUser(){System.out.println("UserController2: user -> " +  user);}
}

在启动类中的 main 方法分别通过 ApplicationContext 获取 UserController1UserController2,然后分别执行其中的方法,观察修改 Bean 对象后产生的影响。

public static void main(String[] args) {ApplicationContext context= new ClassPathXmlApplicationContext("spring-config.xml");UserController1 userController1= context.getBean("userController1", UserController1.class);UserController2 userController2= context.getBean("userController2", UserController2.class);userController1.printUser();System.out.println("=========");userController2.printUser();
}

执行的结果如下:

从运行的结果来看,当 UserController1 修改了 Bean 在数据,此时通过 UserController2 获取的 Bean 的数据也被修改了,那么就说明一个 Bean 在 Spring 中的储存只有一份,并且是单例模式的。因此 Spring 容器中的 Bean 的默认作用域就是单例模式(singleton)的

1.2 作用域的定义

作用域(Scope)是在编程中用于描述变量或标识符在程序中可访问的范围。换句话说,它规定了变量在哪些部分可以被引用和使用。作用域是一个重要的概念,因为它可以帮助程序员避免命名冲突和理解变量在代码中的生命周期

在 Spring 框架中,作用域(Scope)就是用来定义 Bean 对象的生命周期和可见性规则作用域决定了在不同的上下文环境中,Spring 容器如何管理和提供 Bean 对象。例如,在定义一个 Bean 的时候,我们可以指定其作用域,从而决定它在应用程序中的行为表现。

1.3 Bean 的六种作用域

Spring 容器在初始化一个 Bean 的实例的时候,同时会指定该实例的作用域,如果我们不修改要指定的作用域,Spring 就会默认指定一个默认的作用域。以下是 Spring 中的六种作用域,其中最后四种是基于 Spring MVC 生效的,因此本文先不讨论。

  1. 单例作用域(singleton):这是 Spring 容器默认的作用域。在整个应用程序的生命周期中,只会创建一个该类型的 Bean 实例,并且所有对该 Bean 的引用都会执行同一个对象。这种作用域适用于哪些无状态、线程安全的 Bean 对象,例如工具类、配置类等。

  2. 原型作用域(prototype):每次请求 Bean 对象的时候,Spring 容器都会创建一个新的 Bean 实例,因此在不同的请求中,得到的是不同的对象实例。原型作用域适用于那先状态较多,需要频繁创建和销毁的对象,比如某些与会话相关的 Bean。

  3. 请求作用域(request):请求作用域是在 Web 应用中常用的作用域。它表示每次 HTTP 请求都会创建一个新的 Bean 实例,该实例仅在当前请求的处理过程中有效。当请求结束后,该 Bean 会被销毁。这样的作用域通常用于存储和处理与单个请求相关的数据。

  4. 会话作用域(session):会话作用域是在 Web 应用中基于用户会话的作用域。每个 HTTP 会话(Session)对应一个 Bean 实例,该实例在整个会话的生命周期内有效。这种作用域适用于需要在整个会话期间保持状态的对象,比如用户登录信息等。

  5. 全局作用域(application):全局作用域是指在整个 Web 应用程序的生命周期内只创建一个 Bean 实例。该作用域的 Bean 在整个应用中可见,适用于那些在整个应用中需要共享的状态信息。

  6. HTTP WebSocket 作用域(websocket): HTTP WebSocket 作用域是基于 WebSocket 连接的作用域。每个 WebSocket 连接对应一个 Bean 实例,该实例在 WebSocket 连接的整个生命周期内有效。

单例作用域(singleton)和全局作用域(application)之间的区别:

单例作用域和全局作用域都只创建一个 Bean 对象,那么它们之间有什么区别呢?

1. 定义位置:

  • 单例作用域是 Spring Core 的一部分,在整个 Spring IoC 容器中生效。它适用于任何类型的 Spring 应用,不仅限于 Web 应用。
  • 全局作用域是 Spring Web 的一部分,在 Servlet 容器中生效。它是专门为 Web 应用设计的,通过 Spring Web 库提供支持。

2. 作用范围:

  • 单例作用域只保证在 Spring IoC 容器中,每个 Bean 只会有一个实例。在整个应用程序中,不同的 Spring IoC 容器可能会有不同的实例。
  • 全局作用域确保在整个 Web 应用程序中,每个 Bean 只会有一个实例。无论是在同一个 Servlet 容器中还是不同的 Servlet 容器中,都只有一个实例。

3. 应用场景:

  • 单例作用域适用于那些无状态、线程安全的 Bean,例如工具类、配置类等。由于单例 Bean 在整个应用中只有一个实例,因此在性能和资源利用方面有一定的优势。
  • 全局作用域适用于那些在整个 Web 应用中需要共享状态信息的 Bean,比如全局的配置对象、全局缓存等。通过全局作用域,我们可以确保这些对象在整个应用中只有一个实例,而不受多个 Servlet 容器的影响。

4. 管理容器:

  • 单例作用域的管理是 Spring IoC 容器负责的,它由 Spring Core 提供的 IoC 容器管理,与 Web 应用无关。
  • 全局作用域的管理需要由 Spring Web 库提供的 Servlet 容器来管理,它与 Web 应用的生命周期相关。

总结来说,单例作用域适用于整个 Spring IoC 容器,保证每个 Bean 在容器中只有一个实例;而全局作用域适用于整个 Web 应用,保证每个 Bean 在整个应用中只有一个实例。选择合适的作用域取决于具体的应用需求和设计考虑。

1.4 Bean 作用域的设置

在 Spring 中,设置 Bean 作用域可以通过两种方法:XML 配置和注解配置

1. XML 配置
在 XML 配置文件中的 <bean>标签中,可以使用 scope 属性来设置 Bean 的作用域。例如,对于原型作用域的 Bean,可以这样配置:

<bean id="myBean" class="com.spring.demo.MyBean" scope="prototype"><!-- Bean 的属性配置 -->
</bean>

其中,scope指定的是作用域的名称,如:prototype、singleton。

2. 注解配置

使用注解配置 Bean 的作用域更加的简洁。在 Spring 中,可以使用 @Scope 注解来指定 Bean 的作用域,例如对刚才的 UserBeans 类指定原型作用域:

@Component
public class UserBeans {@Bean(name = {"user1"})// @Scope("prototype") // 原型模式@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 使用全局变量设置public User getUser(){User user = new User();user.setId(123);user.setName("张三");return user;}
}

此时,@Scope中的参数可以说作用域的名称,如:prototype;也可以通过ConfigurableBeanFactory类来指定。ConfigurableBeanFactory类的源码:


可以发现ConfigurableBeanFactory类也是对作用域名的封装。

当作用域设置为原型模型的时候,再次运行刚才修改 Bean 内容的代码:

此时就能够发现,两个 UserController 获取到的都是一个全新的 Bean 对象,即使一个修改也不会对另一个造成影响。

二、Spring 的执行流程 和 Bean 的生命周期

2.1 Spring 的执行流程

Spring 执行流程:

  1. 启动 Spring 容器:

    • Spring 容器在启动时会读取配置文件或者扫描注解来获取 Bean 的定义信息。
  2. 实例化 Bean(分配内存空间,从无到有):

    • Spring 容器根据配置信息或者注解的定义,实例化 Bean 对象。实例化过程可能会涉及构造函数的调用和依赖对象的创建。
  3. Bean 注册到 Spring 容器(存操作):

    • 实例化后的 Bean 被注册到 Spring 容器中,容器将其纳入管理范围,并为每个 Bean 分配一个唯一的标识符(通常是 Bean 的名称或者 ID)。
  4. Bean 初始化(初始化操作):

    • 如果 Bean 的定义中配置了初始化方法(例如使用 init-method 属性或者 @PostConstruct 注解),Spring 容器会在实例化之后调用该初始化方法,用于执行一些初始化逻辑。
  5. 将 Bean 装配到需要的类中(取操作):

    • 当其他类需要使用某个 Bean 时,Spring 容器会根据依赖注入的配置,将对应的 Bean 自动注入到需要的类中。这样,其他类就可以直接使用该 Bean 的实例,而不需要关心 Bean 对象的创建和管理过程。
  6. 使用 Bean:

    • 现在,Bean 已经被装配到需要的类中,可以在其他类中直接使用它了。
  7. Bean 销毁(销毁操作):

    • 如果 Bean 的定义中配置了销毁方法(例如使用 destroy-method 属性或者 @PreDestroy 注解),Spring 容器会在容器关闭时调用该销毁方法,用于执行一些清理操作。

需要注意的是,Bean 的生命周期在 Spring 容器的控制下,开发者无需手动管理 Bean 的创建和销毁过程,这就是 Spring IoC(控制反转)的核心思想。通过依赖注入,我们能够更专注于业务逻辑的实现,而不需要关心对象的创建和管理。

2.2 Bean 的生命周期

Bean 的生命周期是指一个 Bean 实例从被创建到被销毁的整个过程。在 Spring 容器中,Bean 的生命周期主要包含以下阶段:

  1. 实例化:这个阶段 Spring 容器会根据配置信息和注解创建 Bean 实例。这是 “从无到有” 的过程,即分配内存空间并调用构造方法来创建 Bean 实例。

  2. 设置属性(Bean 的注入和装配):在实例化后,Spring 容器会根据配置文件或注解,将属性值注入到 Bean 实例中。这是依赖注入(Dependency Injection)的过程,通过属性或构造方法来设置 Bean 的属性值。

  3. Bean 初始化:在属性赋值完成后,Spring 容器会执行以下步骤来初始化 Bean:

    • 各种通知:如果 Bean 实现了相应的 Aware 接口,Spring 会通过回调方式通知 Bean 相应的状态,例如 BeanNameAwareBeanFactoryAwareApplicationContextAware 等。
    • 初始化前置方法:执行 BeanPostProcessor 初始化前置方法,如 postProcessBeforeInitialization
    • 初始化方法(XML方式和注解方式):如果 Bean 定义了初始化方法(@PostConstruct 注解或实现了 InitializingBean 接口),Spring 容器会在设置属性后调用该方法进行进一步的初始化。
    • 初始化后置方法:如果 Bean 定义了初始化后置方法,如 BeanPostProcessor 接口实现类的 postProcessAfterInitialization 方法,Spring 容器会在 Bean 初始化完成后调用该方法。
  4. 使用 Bean:在初始化完成后,Bean 实例就可以被应用程序使用了。它会被注入到其他类中,或者通过 Spring 容器获取并调用它的方法。

  5. 销毁 Bean 对象:在容器关闭或者程序结束时,Spring 容器会执行以下步骤来销毁 Bean:

    • 销毁前置方法:如果 Bean 定义了销毁前置方法(destroy-method),Spring 容器会在 Bean 销毁前调用该方法。
    • 销毁方法(XML方式和注解方式):如果 Bean 定义了销毁方法(@PreDestroy 注解或实现了 DisposableBean 接口),Spring 容器会在 Bean 销毁时调用该方法进行清理操作。

2.3 Bean 生命周期的演示

下面的代码演示了一个完整的 Bean 生命周期过程,并展示了 Spring 中 Bean 的各个阶段的回调方法。让我们来看一下 Bean 生命周期的执行流程:


@Component
public class BeanComponent implements BeanNameAware, BeanPostProcessor {@Overridepublic void setBeanName(String s) {System.out.println("执行了通知,Bean name -> " + s);}// xml 的初始化方法public void myInit(){System.out.println("XML 方式初始化");}@PostConstructpublic void doPostConstruct(){System.out.println("注解 的初始化方法");}public void sayHi(){System.out.println("do sayHi()");}@PreDestroypublic void preDestroy(){System.out.println("do PreDestroy");}// 前置方法@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("do postProcessBeforeInitialization");return bean;}// 后置方法@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("do postProcessAfterInitialization");return bean;}
}

首先需要在 spring-config.xml配置文件中增加以下内容:

<!-- XML 配置方式 --><bean id="beanComponent"class="com.spring.demo.component.BeanComponent" scope="prototype" init-method="myInit" ></bean>

模拟 Bean 的生命周期:

  1. 实例化 Bean:

    • Spring 容器读取配置文件或扫描注解,发现了 BeanComponent 的定义,并实例化了该 Bean。此时,还没有调用 Bean 的构造方法。
  2. 设置属性(Bean 的注入和装配):

    • 如果有需要,Spring 容器会将相应的属性注入到 BeanComponent 实例中。
  3. Bean 初始化:

    • 执行各种通知:因为 BeanComponent 实现了 BeanNameAware 接口,所以 setBeanName 方法会被调用,打印输出 执行了通知,Bean name -> beanComponent
    • 初始化前置方法:如果是 XML 配置方式,myInit 方法会被调用,打印输出 XML 方式初始化
    • 初始化方法(@PostConstruct 注解):doPostConstruct 方法会被调用,打印输出 注解 的初始化方法
    • 初始化后置方法:postProcessAfterInitialization 方法会被调用,打印输出 do postProcessAfterInitialization
  4. 使用 Bean:

    • 在初始化完成后,BeanComponent 实例可以被应用程序使用,例如调用 sayHi() 方法,打印输出 do sayHi()
  5. 销毁 Bean 对象:

    • 在容器关闭或程序结束时,preDestroy 方法会被调用,打印输出 do PreDestroy

需要注意的是,在上述示例中,使用了 BeanPostProcessor 接口来实现前置和后置方法。这个接口提供了在 Bean 初始化前后对 Bean 进行额外处理的能力。在实际应用中,可以通过实现 BeanPostProcessor 接口来自定义一些特定的处理逻辑,例如 AOP 的代理生成。

启动类的main方法:

    public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BeanComponent beanComponent= context.getBean("beanComponent", BeanComponent.class);beanComponent.sayHi();}

执行结果:

这里发现执行了两次通知,第一次通常是因为在创建 Spring 上下文的时候会执行 Bean 的实例化;第二次执行通常是因为采用的是原型模式,当执行getBean的会创建一个新的 Bean 对象。

相关文章:

【Spring】(四)Bean 的作用域和生命周期

文章目录 前言一、Bean 的作用域1.1 被修改的 Bean 案例1.2 作用域的定义1.3 Bean 的六种作用域1.4 Bean 作用域的设置 二、Spring 的执行流程 和 Bean 的生命周期2.1 Spring 的执行流程2.2 Bean 的生命周期2.3 Bean 生命周期的演示 前言 Bean 是 Spring 框架中的一个核心概念…...

卷积神经网络【图解CNN】

文章目录 1.卷积运算2.池化3.全连接层 卷积神经网络可以看作一个函数或者黑箱&#xff0c;输入就是图片的像素阵列&#xff0c;输出就是这个图片是什么&#xff1f; 图片是X&#xff0c;那么就输出‘x’&#xff0c;图片是‘O’,那么就输出O&#xff1b; 在计算机眼中&#xff…...

命令模式 Command Pattern 《游戏设计模式》学习笔记

对于一般的按键输入&#xff0c;我们通常这么做&#xff0c;直接if按了什么键&#xff0c;就执行相应的操作 在这里我们是将用户的输入和程序行为硬编码在一起&#xff0c;这是我们很自然就想到的最快的做法。 但是如果这是一个大型游戏&#xff0c;往往我们需要实现一个按键…...

供水管网漏损监测,24小时保障城市供水安全

供水管网作为城市生命线重要组成部分&#xff0c;其安全运行是城市建设和人民生活的基本保障。随着我国社会经济的快速发展和城市化进程的加快&#xff0c;城市供水管网的建设规模日益增长。然而&#xff0c;由于管网老化、外力破坏和不当维护等因素导致的供水管网漏损&#xf…...

How to Use Glslang

文章目录 Execution of Standalone Wrapper构建 (CMake)依赖关系构建步骤如果需要更改 GLSL 语法测试运行测试基本内部操作 Execution of Standalone Wrapper 要使用独立的二进制形式&#xff0c;请执行glslang&#xff0c;它将打印一条使用语句。基本操作是给它一个包含着色器…...

AcWing 24:机器人的运动范围 ← BFS、DFS

【题目来源】https://www.acwing.com/problem/content/description/22/【题目描述】 地上有一个 m 行和 n 列的方格&#xff0c;横纵坐标范围分别是 0∼m−1 和 0∼n−1。 一个机器人从坐标 (0,0) 的格子开始移动&#xff0c;每一次只能向左&#xff0c;右&#xff0c;上&#…...

RF手机天线仿真介绍(一):金属边框天线和LDS天线

目录 简介LDS天线LDS天线仿真 金属边框天线金属边框天线仿真 简介 最早的手机是外置式天线&#xff0c;从NOKIA开始采用内置式天线&#xff0c;开始采用内置金属片&#xff08;一般是0.1MM厚的不锈钢片冲压而成&#xff09;&#xff0c;随后为降低成本&#xff0c;后来改用FPC…...

动手学深度学习—深度学习计算(层和块、参数管理、自定义层和读写文件)

目录 1. 层和块1.1 自定义块1.2 顺序块1.3 在前向传播函数中执行代码 2. 参数管理2.1 参数访问2.1.1 目标参数2.1.2 一次性访问所有参数2.1.3 从嵌套块收集参数 2.2 参数初始化2.2.1 内置初始化2.2.2 自定义初始化 2.3 参数绑定 3. 自定义层3.1 不带参数的层3.2 带参数的层 4. …...

Pytest学习教程_测试报告生成pytest-html(三)

前言 pytest-html 是一个用于生成漂亮的 HTML 测试报告的 pytest 插件。它可以方便地将 pytest 运行的测试结果转换为易于阅读和理解的 HTML 报告&#xff0c;提供了丰富的测试结果展示功能和交互性。 一、安装 # 版本查看命令 pytest版本&#xff1a; pytest --version pyte…...

模块化原理:source-map

1. webpack打包基本配置 1.安装webpack与webpack-cli npm i webpack webpack-cli 2.配置 "build":"webpack" 3. 新建webpack.config.js const path require(path); module.exports {// mode: "development",// 默认production&#xff08;什么…...

【C++】开源:ncurses终端TUI文本界面库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍ncurses终端文本界面库。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…...

C语言的_Bool类型

C99 新增了 _Bool 类型&#xff0c;用于表示布尔值&#xff0c;即逻辑值 true 和 false。 _Bool 类型也是一种整数类型。 原则上 _Bool 类型只占用一位存储空间。 C语言将非 0 的数当为 true&#xff0c;0 当为 false。 代码示例&#xff1a; #include<stdio.h> int…...

【python爬虫】获取某一个网址下面抓取所有的a 超链接下面的内容

import requests as rq from bs4 import BeautifulSoup as bs import re# rooturl是传的是我需要查询和抓取的一个网址&#xff0c;可以是html js 等 def gethtml(rooturl, encoding"utf-8"):#默认解码方式utf-8response rq.get(rooturl)response.encoding encodin…...

AutoDL从0到1搭建stable-diffusion-webui

前言 AI绘画当前非常的火爆&#xff0c;随着Stable diffusion&#xff0c;Midjourney的出现将AI绘画推到顶端&#xff0c;各大行业均受其影响&#xff0c;离我们最近的AI绘画当属Stable diffusion&#xff0c;可本地化部署&#xff0c;只需电脑配备显卡即可完成AI绘画工作&…...

手动调整broker扩容后的旧topic分区

在broker扩容了两台机器之后&#xff0c;想让旧topic&#xff1a;quickstart76-events的分区也能铺满broker 1、创建一个topics-to-move.json json文件 $ vim topics-to-move.json json {"topics": [{"topic":"quickstart76-events"}],"v…...

【LeetCode-简单】剑指 Offer 25. 合并两个排序的链表(详解)

题目 入两个递增排序的链表&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1&#xff1a; 输入&#xff1a;1->2->4, 1->3->4 输出&#xff1a;1->1->2->3->4->4 本题与主站 21 题相同&#xff1a;力扣 题目地址&#x…...

Java版工程行业管理系统源码-专业的工程管理软件-em提供一站式服务

​ Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目…...

【Spring】简化事件的使用,Spring提供了2种使用方式

Spring中事件可以配置顺序&#xff0c;利用线程池还可以做异步线程通知。怎么样使用事件&#xff1f;Spring简化事件的使用&#xff0c;Spring提供了2种使用方式&#xff1a;面向接口和面向EventListener注解。 1,面相接口的方式 案例 发布事件 需要先继承ApplicationEventP…...

探究Spring事务:了解失效场景及应对策略

在现代软件开发中&#xff0c;数据的一致性和完整性是至关重要的。为了保证这些特性&#xff0c;Spring框架提供了强大的事务管理机制&#xff0c;让开发者能够更加自信地处理数据库操作。然而&#xff0c;事务并非银弹&#xff0c;存在一些失效的情景&#xff0c;本文将带您深…...

Maven Manifold 条件编译

Maven 配置 通过 Maven 的不同 profile 实现不同环境传递不同符号。另外 lombok 可以 manifold 一同使用&#xff0c;见下方配置。 <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.targ…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...