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

第2章——springboot核心机制


一、为何以继承方式引入SpringBoot

1.提出疑问

以前我们在开发项目时,需要什么,引入对应的依赖就行,比如我们需要连接mysql数据,则引入mysql驱动的依赖,如下:

<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.3.0</version>
</dependency>

现在我们要使用SpringBoot框架,按说也应该采用依赖的方式将SpringBoot框架引入,如下:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.3</version>
</dependency>

但是SpringBoot官方推荐的不是直接引入依赖,而是采用继承的方式实现,如下:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.3</version>
</parent>

为什么

2.作为父项目和作为依赖的区别

继承父工程的优势

  • 依赖管理:可以在父工程中定义依赖的版本,子模块可以直接引用而不必指定版本号。

  • 插件管理:可以在父工程中配置常用的插件及其版本,子模块可以直接使用这些配置。

  • 属性设置:可以在父工程中定义一些通用的属性,如项目编码、Java 版本等。

  • 统一配置:可以统一多个子模块的构建配置,确保一致性。

直接引入依赖的局限性(如果你不使用继承父工程的方式,而是通过直接引入依赖的方式来管理项目,那么你将失去上述的一些优势)

  • 依赖版本管理:每个子模块都需要单独指定依赖的版本,这会导致大量的重复配置,并且难以维护。

  • 插件配置:每个子模块都需要单独配置插件及其版本,无法共享父工程中的插件配置。

  • 属性设置:每个子模块都需要单独设置通用的属性,如项目编码、Java 版本等。

  • 构建配置:每个子模块的构建配置需要单独维护,难以保证一致性。

总结:选择哪种方式取决于你的具体需求。

  • 如果你希望多个项目之间共享构建配置,那么使用父项目是一个好的选择;

  • 如果你只是想在项目之间共享代码,那么应该使用依赖关系。

3.原理揭晓

通过源码来分析一下:


通过上图源码可以看到Spring Boot预先对开发中需要用到的依赖进行了版本的统一管理。我们需要和SpringBoot框架共享这个构建配置。因此官方推荐使用继承的方式引入SpringBoot框架。

3.依赖统一管理的好处

Spring Boot 框架的一个重要特性就是简化了项目依赖管理。它通过提供一个叫做“依赖管理”的功能来帮助开发者更容易地管理和使用第三方库和其他 Spring 组件。具体来说,Spring Boot 提供了一个包含多个 Spring 和其他常用库的依赖版本配置文件(通常是在 spring-boot-dependencies 文件中),这使得开发者不需要在自己的项目中显式指定这些依赖的版本号。

这样做有以下几个好处:

  • 简化依赖声明: 开发者只需要在 pom.xml 文件中声明需要的依赖而不需要指定其版本号,因为 Spring Boot 已经为这些依赖指定了版本。例如,如果你需要使用mysql驱动,你只需要添加相应的依赖声明而不需要关心版本。

<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId>
</dependency>
  • 避免版本冲突: 当多个库之间存在依赖关系的时候,如果手动管理版本可能会导致版本之间的冲突(即“依赖地狱”)。Spring Boot 提供的统一版本管理可以减少这种冲突的可能性。

  • 易于升级: 当 Spring Boot 发布新版本时,通常会更新其依赖库到最新稳定版。因此,当你升级 Spring Boot 版本时,它所管理的所有依赖也会随之更新到兼容的版本。

  • 减少配置错误: 由于 Spring Boot 自动处理了依赖的版本,减少了手动输入版本号可能引入的拼写或格式错误。

  • 提高开发效率: 开发者可以专注于业务逻辑的编写,而不是花费时间在解决依赖问题上。

总的来说,Spring Boot 的依赖管理功能使得开发者可以更加专注于业务逻辑的实现,同时减少了因依赖版本不一致而引发的问题,提高了项目的可维护性和开发效率。


当然,如果你在项目中需要更改某个依赖的版本号,不想使用SpringBoot框架指定的版本号,只需要在引入依赖时强行执行版本号即可,maven是支持就近原则的:

这样做就是采用SpringBoot指定版本的依赖:

<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId>
</dependency>

这样做就是不采用SpringBoot指定版本的依赖:

<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.2.0</version>
</dependency>

二、Starter-启动器

在 Spring Boot 中,启动器(Starter)本质上是一个简化依赖管理的概念。

Spring Boot 的启动器本质上就是一组预定义的依赖集合,它们被组织成一个个 Maven的依赖,以方便开发者快速集成特定的功能模块。

如果你想做web开发,只需要引入web启动器。web启动器会自动引入web开发所需要的子依赖。

1.启动器实现原理

  1. 依赖聚合: 每个启动器通常对应一个特定的功能集或者一个完整的应用模块,如 spring-boot-starter-web 就包含了构建 Web 应用所需的所有基本依赖项,如 Spring MVC, Tomcat 嵌入式容器等。

  2. 依赖传递: 当你在项目中引入一个启动器时,它不仅会把自身作为依赖加入到你的项目中,还会把它的所有直接依赖项(transitive dependencies)也加入进来。这意味着你不需要单独声明这些依赖项,它们会自动成为项目的一部分。

  3. 版本管理: 启动器内部已经指定了所有依赖项的具体版本,这些版本信息存储在一个公共的 BOM(Bill of Materials,物料清单)文件中,通常是 spring-boot-dependencies。当引入启动器时,实际上也间接引用了这个 BOM,从而确保了所有依赖项版本的一致性。

  4. 自动配置: 许多启动器还提供了自动配置(Auto-configuration),这是一种机制,允许 Spring Boot 根据类路径上的可用组件自动设置你的应用程序。例如,如果类路径上有 Spring MVC 和嵌入式 Tomcat,则 Spring Boot 会自动配置它们,并准备好一个 web 应用程序。

使用启动器的示例

假设你想创建一个基于 Spring MVC 的 RESTful Web 应用,你可以简单地将 spring-boot-starter-web 添加到你的项目中:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

当你添加这个依赖时,Spring Boot 会处理所有必要的细节,包括添加 Spring MVC 和 Tomcat 作为嵌入式 Servlet 容器,并且根据类路径上的内容进行适当的自动配置。如下图所示:

这就是 Spring Boot 启动器的基本实现原理,它简化了依赖管理,让开发者能够更专注于业务逻辑的实现。

2.都有哪些启动器

启动器通常包括:

  • SpringBoot官方提供的启动器

  • 非官方提供的启动器

官方提供的启动器

启动器命名特点:spring-boot-starter-*

非官方的启动器

启动器命名特点:*-spring-boot-starter

三、Spring Boot核心注解

创建一个新的模块,来学习Spring Boot核心注解:

1.@SpringBootApplication注解

Spring Boot的主入口程序被@SpringBootApplication注解标注,可见这个注解的重要性,查看它的源码:

可以看出这个注解属于组合注解。拥有@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan的功能。

2.@SpringBootConfiguration注解

@SpringBootConfiguration注解的源码如下:

可以看到这个注解的被@Configuration标注,说明主入口程序是一个配置类。也就是说主入口中的方法可以被@Bean注解标注,被@Bean注解的标注的方法会被Spring容器自动调用,并且将该方法的返回对象纳入IoC容器的管理。

SpringBoot主入口类实际上就是一个配置类

这个配置类也可以称为,起源的意思,SpringBoot从这个配置类开始加载项目中所有的bean。

3.@EnableAutoConfiguration注解

该注解表示`启用自动配置`

Spring Boot 会根据你引入的依赖自动为你配置好一系列的 Bean,无需手动编写复杂的配置代码。

例如:如果你在SpringBoot项目中进行了如下配置:

关于 @EnableAutoConfiguration 注解:启用自动配置。也就是说默认情况下,springboot应用都会默认启用自动配置。自动配置有什么用?所谓的自动配置只要启动,springboot应用会去类路径当中查找class,根据类路径当中有某个类,或某些类,来自动管理bean,不需要我们程序员手动配置。比如:springboot检测到类路径当中有 SqlSessionFactory,或者在application.properties文件中配置了数据源,那么springboot会认为项目中有mybatis框架,因此会将mybatis中相关的bean自动初始化,然后放到IoC容器当中,自动将这些bean管理起来。sqlSessionFactorytransactionManager

并且在依赖中引入了mybatis依赖/mybatis启动器,那么SpringBoot框架将为你自动化配置以下bean:

  • SqlSessionFactory: MyBatis的核心工厂SqlSessionFactory会被自动配置。这个工厂负责创建SqlSession实例,后者用来执行映射文件中的SQL语句。

  • TransactionManager: DataSourceTransactionManager会被自动配置来管理与数据源相关的事务。

4.@ComponentScan注解

这个注解的作用是:启动组件扫描功能,代替spring框架xml文件中这个配置:

<context:component-scan base-package="com.powernode.sb305core"/>

因此被`@SpringBootApplication`注解标注之后,会启动组件扫描功能,扫描的包是`主入口程序所在包及子包`,因此如果一个bean要纳入IoC容器的管理则必须放到主入口程序所在包及子包下。放到主入口程序所在包之外的话,扫描不到。测试一下:


结论:要让bean纳入IoC容器的管理,必须将类放到主入口程序同级目录下,或者子目录下。

四、Spring Boot的单元测试

1.不使用单元测试怎么调用service

User

package org.example1.springboot03.bean;public class User {private String username;private String password;@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +'}';}public User(String username, String password) {this.username = username;this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

service:

入口:

测试:

2.使用单元测试怎么调用service

⑴.test-starter引入以及测试类编写

使用单元测试应该如何调用service对象上的方法呢?

在使用脚手架创建Spring Boot项目时,为我们生成了单元测试类,如下:

要使用单元测试,需要引入单元测试启动器,如果使用脚手架创建SpringBoot项目,这个test启动器会自动引入:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>

⑵.@SpringBootTest注解

@SpringBootTest 会创建一个完整的 Spring 应用程序上下文(Application Context),这个上下文包含了应用程序的所有组件和服务。以下是 @SpringBootTest 做的一些主要工作:

  1. 创建 ApplicationContext

    • @SpringBootTest 使用 SpringApplicationrun() 方法来启动一个 Spring Boot 应用程序上下文。这意味着它会加载应用程序的主配置类和其他相关的配置类。

  2. 加载配置文件

    • 它会查找并加载默认的配置文件,如 application.properties

  3. 自动配置

    • 如果应用程序依赖于 Spring Boot 的自动配置特性,@SpringBootTest 会确保这些自动配置生效。这意味着它会根据可用的类和bean来自动配置一些组件,如数据库连接、消息队列等。

  4. 注入依赖

    • 使用 @SpringBootTest 创建的应用程序上下文允许你在测试类中使用 @Autowired 注入需要的 bean,就像在一个真实的 Spring Boot 应用程序中一样。

总的来说,@SpringBootTest 为你的测试提供了尽可能接近实际运行时环境的条件,这对于验证应用程序的行为非常有用。

测试结果如下:

五、外部化配置

1.什么是外部化配置

外部化配置是指:将配置信息存储在应用程序代码之外的地方。这样配置信息可以独立于代码进行管理。这样方便了配置的修改,并且修改后不需要重新编译代码,也不需要重新部署项目。

⑴.外部化配置的方式

SpringBoot支持多种外部化配置方式,包括但不限于:

  • properties文件

  • YAML文件

  • 系统环境变量

  • 命令行参数

  • ......

⑵.外部化配置的优势

  1. 灵活性:配置文件可以独立于应用程序部署,这使得可以根据运行环境的不同来调整配置,而无需修改代码。

  2. 易于维护:配置变更不需要重新构建和部署应用程序,降低了维护成本。

  3. 安全性:敏感信息如数据库密码、API密钥等可以存储在外部,并且可以限制谁有权限访问这些配置信息。

  4. 共享性:多实例或多服务可以共享相同的配置信息,减少重复配置的工作量。

  5. 版本控制:配置文件可以存放在版本控制系统中,便于跟踪历史版本和回滚配置。

总之,外部化配置使得配置更加灵活、安全、易于管理和共享,是现代云原生应用中非常推荐的做法

⑶.外部化配置对比传统配置

在传统的SSM三大框架中,如果修改XML的配置后,需要对应用重新打包,重新部署。

使用SpringBoot框架的外部化配置后,修改配置后,不需要对应用重新打包,也不需要重新部署,最多重启一下服务即可。

2.application.properties

application.properties配置文件是SpringBoot框架默认的配置文件。

application.properties不是必须的,SpringBoot对于应用程序来说,都提供了一套默认配置(就是我们所说的自动配置)。

如果你要改变这些默认的行为,可以在application.properties文件中进行配置。

application.properties可以放在类路径当中,也可以放在项目之外。因此称为外部化配置。

Spring Boot 框架在启动时会尝试从以下位置加载 application.properties 配置文件:


Spring Boot 加载application.properties或application.yml配置文件的位置顺序。


Spring Boot 会按照这个顺序来加载配置文件,如果在多个位置有相同的属性定义,那么最先检查的位置中的属性值将优先使用。

如果你想要指定其他的配置文件位置或者改变默认的行为,可以通过 --spring.config.location= 后跟路径的方式来指定配置文件的具体位置。例如 :

java -jar sb3-01-first-web-1.0-SNAPSHOT.jar 
--spring.config.location=file:///E:\a\b\application.properties

这样,Spring Boot 将会首先从 E:\a\b\ 这个路径加载配置文件。注意,这种方式可以用来覆盖默认的配置文件位置,并且可以结合以上提到的位置一起使用。

注意:以上的--spring.config.location=file:///E:\a\b\application.properties就属于命令行参数,它将来会被传递到main方法的(String[] args)参数上。

3.使用@Value注解

@Value注解可以将application.properties/application.yml文件中的配置信息注入/绑定到java对象的属性上。

语法格式:@Value("${key}")

使用脚手架创建SpringBoot项目,不添加任何启动器:

使用@Value注解时也可以指定默认值,当指定默认值时,如果配置文件中没有指定配置值,则采用默认值。

语法格式:@Value("${key:defalut}")

@Service("userService")
public class UserService {@Value("${myapp.username}")private String username;@Value("${myapp.email}")private String email;@Value("${myapp.age}")private Integer age;@Value("${myapp.password:123456}")private String password;public void printInfo(){String str = String.join(",", username, email, String.valueOf(age), password);System.out.println(str);}
}

4.YAML

YAML概述

SpringBoot采用集中式配置管理,所有的配置都编写到一个配置文件中:application.properties

如果配置非常多,层级不够分明,因此SpringBoot为了提高配置文件可读性,也支持YAML格式的配置文件:application.yml

YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,它通常用于配置文件,在各种编程语言中作为一种存储或传输数据的方式。YAML的设计目标是易于阅读和编写,同时保持足够的表达能力来表示复杂的数据结构。

YAML文件的扩展名可以是.yaml.yml

常见的数据存储和交换格式

propertiesXMLJSONYAML这几种格式确实是用来存储和交换数据的常见方式,但它们各有特点和适用场景:

Properties

  • 这种格式主要用于Java应用程序中的配置文件。它是键值对的形式,每一行是一个键值对,使用等号或冒号分隔键和值。

  • 特点是简单易懂,但在处理复杂结构的数据时显得力不从心。

XML (eXtensible Markup Language)

  • XML是一种标记语言,用来描述数据的格式。它支持复杂的数据结构,包括嵌套和属性。

  • XML文档具有良好的结构化特性,适合传输和存储结构化的数据。但是,XML文档通常体积较大,解析起来也比较耗资源。

JSON (JavaScript Object Notation)

  • JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,支持多种数据类型,如数字、字符串、布尔值、数组和对象。

  • JSON因为简洁和高效而广泛应用于Web应用程序之间进行数据交换。

YAML (YAML Ain't Markup Language)

  • YAML设计的目标之一就是让人类更容易阅读。它支持类似JSON的数据序列化,但提供了更多的灵活性,例如缩进来表示数据结构。

  • YAML非常适合用来编写配置文件,因为它允许以一种自然的方式组织数据,并且可以包含注释和其他人类可读的元素。

总结来说,这四种格式都可以用来存储和交换数据,但它们的设计初衷和最佳使用场景有所不同。选择哪种格式取决于具体的应用需求、数据复杂度、性能要求等因素。

YAML的语法规则

YAML的语法规则如下:

  1. 数据结构:YAML支持多种数据类型,包括:

    1. 字符串、数字、布尔值

    2. 数组、list集合

    3. map键值对 等。

  2. YAML使用一个空格来分隔属性名属性值,例如:

    1. properties文件中这样的配置:name=jack

    2. yaml文件中需要这样配置:name: jack

  3. YAML用换行+空格来表示层级关系。注意不能使用tab,必须是空格,空格数量无要求,大部分建议2个或4个空格。例如:

    1. properties文件中这样的配置:myapp.name=mall

    2. yaml文件中就需要这样配置:

myapp:name: mall

4.同级元素左对齐。

         1.例如: properties文件中有这样的配置:

myapp.name=mall
myapp.count=10

          2. `yaml`文件中就应该这样配置:

myapp:name: mallcount: 10

5.键必须是唯一的:在一个映射中,键必须是唯一的。

6.注释:使用#进行注释。

7.大小写敏感

YAML的使用小细节

第一:普通文本也可以使用单引号或双引号括起来:(当然普通文本也可以不使用单引号和双引号括起来。)

  • 单引号括起来:单引号内所有的内容都被当做普通文本,不转义(例如字符串中有\n,则\n被当做普通的字符串)

  • 双引号括起来:双引号中有 \n 则会被转义为换行符

第二:保留文本格式

  • | 将文本写到这个符号的下层,会自动保留格式。

第三:文档切割

  • --- 这个符号下面的配置可以认为是一个独立的yaml文件。便于庞大文件的阅读。

# 普通文本引号使用示例
# 不使用引号
plainTextNoQuotes: 这是一段普通文本
# 使用单引号
plainTextSingleQuotes: '这是一段包含 \n 的普通文本,\n 不会被转义'
# 使用双引号
plainTextDoubleQuotes: "这是一段包含 \n 的普通文本,\n 会被转义为换行符"# 保留文本格式示例
preserveFormat: |这是一段保留格式的文本。它会按照这里的格式进行显示。每行内容都会保持原有的换行。# 文档切割示例
---
# 这部分配置可以认为是一个独立的yaml文件
newDocument:key1: value1key2: value2
---
# 又一个独立的配置文档
anotherDocument:item1: 123item2: 456

application.yml

Spring Boot框架同时支持propertiesyaml

在 Spring Boot 里,当同一个目录下同时存在application.propertiesapplication.yml文件时,application.properties文件会被优先解析。

resources/config目录下新建application.yml文件,进行如下配置:



5.配置文件合并

一个项目中所有的配置全部编写到application.properties文件中,会导致配置臃肿,不易维护,有时我们会将配置编写到不同的文件中,例如:

application-mysql.properties专门配置mysql的信息,

application-redis.properties专门配置redis的信息,最终将两个配置文件合并到一个配置文件中。

properties文件

创建配置文件

src/main/resources目录下创建以下三个配置文件:

application.properties

spring.config.import=application-mysql.properties,application-redis.properties

这里使用spring.config.import属性来引入其他配置文件,多个文件之间用逗号分隔。

application-mysql.properties

mysql.host=localhost
mysql.port=3306
mysql.username=root
mysql.password=password

此文件用于配置 MySQL 相关信息。

application-redis.properties

redis.host=localhost
redis.port=6379
redis.password=redis_password

这个文件用于配置 Redis 相关信息。


yaml文件

application-mysql.yml

spring:datasource:username: rootpassword: 789789

application-redis.yml

spring:data:redis:host: localhostport: 6379

application.yml

spring:config:import:- classpath:application-mysql.yml- classpath:application-redis.yml

6.多环境切换

在Spring Boot中,多环境切换是指在一个应用程序中支持多种运行环境配置的能力。这通常用于区分开发(development)、测试(testing)、预生产(staging)和生产(production)等不同阶段的环境。

这种功能使得开发者能够在不同的环境中使用不同的配置,比如数据库连接信息、服务器端口、环境变量等,而不需要更改代码。这对于维护一个可移植且易于管理的应用程序非常重要。

开发环境的配置文件名一般叫做:application-dev.properties

spring.datasource.username=dev
spring.datasource.password=dev123
spring.datasource.url=jdbc:mysql://localhost:3306/dev

测试环境的配置文件名一般叫做:application-test.properties

spring.datasource.username=test
spring.datasource.password=test123
spring.datasource.url=jdbc:mysql://localhost:3306/test

预生产环境的配置文件名一般叫做:application-preprod.properties

spring.datasource.username=preprod
spring.datasource.password=preprod123
spring.datasource.url=jdbc:mysql://localhost:3306/preprod

生产环境的配置文件名一般叫做:application-prod.properties

spring.datasource.username=prod
spring.datasource.password=prod123
spring.datasource.url=jdbc:mysql://localhost:3306/prod

如果你希望该项目使用生产环境的配置,你可以这样做:

第一种方式:在 application.properties 文件中添加配置

在 application.properties 文件里添加以下内容:

spring.profiles.active=prod

第二种方式:在命令行参数上添加配置

假设你运用的是 Java 程序,以下是启动时添加命令行参数的示例:

java -jar your-application.jar --spring.profiles.active=prod

若你使用的是 Maven 来运行项目,示例如下:

mvn spring-boot:run -Dspring-boot.run.arguments=--spring.profiles.active=prod

要是你运用的是 Gradle 来运行项目,示例如下:

gradle bootRun --args='--spring.profiles.active=prod'

7.将配置绑定到bean

绑定简单bean

SpringBoot配置文件中的信息除了可以使用@Value注解读取之外,也可以将配置信息一次性赋值给Bean对象的属性。

例如有这样的配置:

Bean需要这样定义:

说明:

1.被绑定的bean,需要使用@ConfigurationProperties(prefix = "app")注解进行标注,prefix用来指定前缀

bean中的所有属性都提供了setter方法。因为底层是通过setter方法给bean属性赋值的。

2.这样的bean需要使用@Component注解进行标注,纳入IoC容器的管理。@Component注解负责创建Bean对象,@ConfigurationProperties(prefix = "app")注解负责给bean对象的属性赋值。

3.bean的属性需要是非static的属性。

编写测试程序,将bean对象输出,结果如下:

@Configuration注解

以上操作中使用了@Component注解进行了标注,来纳入IoC容器的管理。也可以使用另外一个注解@Configuration,用这个注解将Bean标注为配置类。多数情况下我们会选择使用这个注解,因为该Bean对象的属性对应的就是配置文件中的配置信息,因此这个Bean我们也可以将其看做是一个配置类。

绑定嵌套bean

当一个Bean中嵌套了一个Bean,这种情况下可以将配置信息绑定到该Bean上吗?当然可以。

有这样的一个配置:

需要编写这样的两个Bean:

执行测试程序,结果如下:

@EnableConfigurationProperties与@ConfigurationPropertiesScan

AppBean纳入IoC容器的管理,之前我们说了两种方式:第一种是使用@Component,第二种是使用@Configuration。SpringBoot其实还提供了另外两种方式:

  • 第一种:@EnableConfigurationProperties

  • 第二种:@ConfigurationPropertiesScan

这两个注解都是标注在SpringBoot主入口程序上的:



运行测试:

将配置赋值到Bean的Map/List/Array属性上

代码如下:

package org.example1.springboot310configbindtobean.bean;import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.Arrays;
import java.util.List;
import java.util.Map;@ConfigurationProperties(prefix = "app2.abc")
public class AppBean {// 数组:数组中元素是简单类型private String[] names;// 数组:数组中元素是beanprivate Address[] addrArray;// List集合:集合中的元素是beanprivate List<Address> addrList;// Map集合:String,Beanprivate Map<String, Address> addrs;public void setNames(String[] names) {this.names = names;}public void setAddrArray(Address[] addrArray) {this.addrArray = addrArray;}public void setAddrList(List<Address> addrList) {this.addrList = addrList;}public void setAddrs(Map<String, Address> addrs) {this.addrs = addrs;}@Overridepublic String toString() {return "AppBean{" +"names=" + Arrays.toString(names) +", addrArray=" + Arrays.toString(addrArray) +", addrList=" + addrList +", addrs=" + addrs +'}';}
}

配置信息如下:

测试:


补充yml的写法:

将配置绑定到第三方对象

将配置文件中的信息绑定到某个Bean对象上,如果这个Bean对象没有源码,是第三方库提供的,怎么办?

此时可以单独编写一个方法,在方法上使用以下两个注解进行标注:

  • @Bean

  • @ConfigurationProperties

假设我们有这样一个类Address(假设这个Address是第三方写的,我们无权修改,代码如下:

实现代码如下:

测试代码:

指定数据来源

指定数据的来源用的

之前所讲的内容是将Spring Boot框架默认的配置文件application.propertiesapplication.yml作为数据的来源绑定到Bean上。如果配置信息没有在默认的配置文件中呢?可以使用@PropertySource注解指定配置文件的位置,这个配置文件可以是.properties,也可以是.xml。这里重点掌握.properties即可。

resources目录下新建a目录,在a目录下新建b目录,b目录中新建group-info.properties文件,进行如下的配置:

定义Java类`Group`,然后进行注解标注:

以下三个注解分别起到什么作用:

  • @Configuration:指定该类为配置类,纳入Spring容器的管理

  • @ConfigurationProperties(prefix = "group"):将配置文件中的值赋值给Bean对象的属性

  • @PropertySource("classpath:a/b/group-info.properties"):指定额外的配置文件

编写测试程序,测试结果如下:

8.@ImportResource注解

创建Bean的三种方式总结:

  • 第一种方式:编写applicationContext.xml文件,在该文件中注册Bean,Spring容器启动时实例化配置文件中的Bean对象。

  • 第二种方式:@Configuration注解结合@Bean注解。

  • 第三种方式:@Component、@Service、@Controller、@Repository等注解。

第二种和第三种我们都已经知道了。针对第一种方式,如果在SpringBoot框架中应该怎么实现呢?使用@ImportResource注解实现

定义一个普通的Java类:Person

package org.example1.springboot310configbindtobean.bean;public class Person {private String name;private int age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

resources目录下新建applicationContext.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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="person" class="org.example1.springboot310configbindtobean.bean.Person"><property name="name" value="jackson"/><property name="age" value="20"/></bean></beans>

在SpringBoot主入口类上添加@ImportResource进行资源导入,这样applicationContext.xml文件中的Bean将会纳入IoC容器的管理:

编写测试程序,看看是否可以获取到person这个bean对象:

因此,项目中如果有类似于Spring的这种xml配置文件,要想纳入IoC容器管理,需要在入口类上使用@ImportResource("classpath:applicationContext.xml")注解即可。

9.Environment

SpringBoot框架在启动的时候会将系统配置,环境信息全部封装到Environment对象中,如果要获取这些环境信息,可以调用Environment接口的方法。

在Spring Boot中,Environment接口提供了访问应用程序环境信息的方法,比如活动配置文件、系统环境变量、命令行参数等。Environment接口由Spring框架提供,Spring Boot应用程序通常会使用Spring提供的实现类AbstractEnvironment及其子类来实现具体的环境功能。

Environment对象封装的主要数据包括:

  1. Active Profiles: 当前激活的配置文件列表。Spring Boot允许应用程序定义不同的环境配置文件(如开发环境、测试环境和生产环境),通过激活不同的配置文件来改变应用程序的行为。

  2. System Properties: 系统属性,通常是操作系统级别的属性,比如操作系统名称、Java版本等。

  3. System Environment Variables: 系统环境变量,这些变量通常是由操作系统提供的,可以在启动应用程序时设置特定的值。

  4. Command Line Arguments: 应用程序启动时传递给主方法的命令行参数。

  5. Property Sources: Environment还包含了一个PropertySource列表,这个列表包含了从不同来源加载的所有属性。PropertySource可以来自多种地方,比如配置文件、系统属性、环境变量等。

在Spring Boot中,可以通过注入Environment来获取上述信息。例如:

通过这种方式,你可以根据环境的不同灵活地配置你的应用程序。Environment是一个非常有用的工具,它可以帮助你管理各种类型的配置信息,并根据不同的运行时条件做出相应的调整。

六、Spring Boot中如何进行AOP的开发

1.Spring Boot AOP概述

面向切面编程AOP在Spring教程中已经进行了详细讲解,这里不再赘述,如果忘记的同学,可以重新听一下Spring教程中AOP相关的内容。这里仅带着大家在Spring Boot中实现AOP编程。

Spring Boot的AOP编程和Spring框架中AOP编程的唯一区别是:引入依赖的方式不同。其他内容完全一样。Spring Boot中AOP编程需要引入aop启动器:

<!--aop启动器-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

可以看到,当引入aop启动器之后,会引入aop依赖aspectj依赖

  • aop依赖:如果只有这一个依赖,也可以实现AOP编程,这种方式表示使用了纯Spring AOP实现aop编程。

  • aspectj依赖:一个独立的可以完成AOP编程的AOP框架,属于第三方的,不属于Spring框架。(我们通常用它,因为它的功能更加强大)

2.Spring Boot AOP实现

实现功能:项目中很多service,要求执行任何service中的任何方法之前记录日志。

创建Spring Boot项目引入aop启动器

<!--aop启动器-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

编写service并提供方法

package org.example1.springboot311aop.service;public interface UserService {/*** 保存用户信息* @param id 用户id* @param name 用户名*/void save(Long id, String name);/*** 根据id删除用户* @param id 用户id*/void deleteById(Long id);
}

package org.example1.springboot311aop.service.impl;import org.example1.springboot311aop.service.UserService;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserService {@Overridepublic void save(Long id, String name) {System.out.println("正在保存用户信息:" + name);}@Overridepublic void deleteById(Long id) {System.out.println("正在删除用户" + id + "信息");}
}

编写切面

测试

相关文章:

第2章——springboot核心机制

一、为何以继承方式引入SpringBoot 1.提出疑问 以前我们在开发项目时&#xff0c;需要什么&#xff0c;引入对应的依赖就行&#xff0c;比如我们需要连接mysql数据&#xff0c;则引入mysql驱动的依赖&#xff0c;如下&#xff1a; <dependency><groupId>com.mys…...

huggingface 热门开源TTS模型Dia-1.6B,支持多人对话生成、情感控制~

简介 Dia-1.6B 是一款由 Nari Labs 开发的开源文本转语音&#xff08;TTS&#xff09;模型&#xff0c;专注于生成自然对话。其项目背景和模型架构基于近期可用的网络信息进行了详细分析&#xff0c;以下是全面的报告。 项目背景概述 Dia-1.6B 的开发始于 Nari Labs&#xff…...

深入理解West:介绍、使用及与Repo的对比

目录 引言 West简介 West的由来 West的核心功能 West的架构与工作流程 West安装与使用 环境准备与安装 Manifest 文件结构解析 常用命令详解与进阶用法 Tip与Troubleshoot 实践案例:基于West的Zephyr项目管理 初始化与同步 构建与闪存 插件示例:自定义命令 Repo简介 Repo的背…...

力扣-hot100 (矩阵置零)

73. 矩阵置零 中等 给定一个 *m* x *n* 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示…...

OpenKylin安装Elastic Search8

一、环境准备 Java安装 安装过程此处不做赘述&#xff0c;使用以下命令检查是否安装成功。 java -version 注意&#xff1a;Elasticsearch 自 7.0 版本起内置了 OpenJDK&#xff0c;无需单独安装。但如需自定义 JDK&#xff0c;可设置 JAVA_HOME。 二、安装Elasticsearch …...

【JVM】从零开始深度解析JVM

本篇博客给大家带来的是JVM的知识点, 重点在类加载和垃圾回收机制上. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; …...

制造企业PLM系统成本基准:2025年预算分配与资源成本率的5种优化模型

在 2025 年制造业数字化转型的浪潮中&#xff0c;PLM&#xff08;产品生命周期管理&#xff09;系统已成为制造企业提升核心竞争力的关键工具。然而&#xff0c;PLM 系统的实施和运营成本较高&#xff0c;如何有效控制成本、优化预算分配和资源成本率&#xff0c;成为企业关注的…...

【Python】一键提取视频音频并生成MP3的完整指南 by `MoviePy`

摘要 昨天&#xff0c; 我在让一个小朋友给我整理一次培训的视频的时候&#xff0c;我看到他把视频文件放到剪映里面处理。 我以为他要干什么呢&#xff0c; 还很期待&#xff0c;结果他只是为了导出音频而已。 于是就有了今天的这篇博客。 作为音视频处理领域的常用需求&…...

Golang领域Beego框架的中间件开发实战

在Golang的Beego框架中&#xff0c;中间件&#xff08;Middleware&#xff09;是一种强大的机制&#xff0c;用于在请求处理的不同阶段插入自定义逻辑。 中间件可以用于处理日志记录、身份验证、错误处理、请求/响应修改等任务。 Beego框架中间件开发的实战指南&#xff1a; …...

Elasticsearch:我们如何在全球范围内实现支付基础设施的现代化?

作者&#xff1a;来自 Elastic Kelly Manrique SWIFT 和 Elastic 如何应对基础设施复杂性、误报问题以及日益增长的合规要求。 金融服务公司在全球范围内管理实时支付方面面临前所未有的挑战。SWIFT&#xff08;Society for Worldwide Interbank Financial Telecommunication -…...

【LLIE专题】基于 CLIP 的无监督背光增强算法

CLIP-LIT: Iterative Prompt Learning for Unsupervised Backlit Image Enhancement&#xff08;2023&#xff0c;ICCV&#xff09; 专题介绍一、研究背景二、CLIP-LIT方法三、实验结果四、总结五、思考 本文将对 CLIP-LIT: Iterative Prompt Learning for Unsupervised Backl…...

深入了解酒店一次性牙刷:材质选择与设计考量全解析

酒店的一次性牙刷是我们住酒店时常见的用品&#xff0c;它方便了很多旅客出行&#xff0c;虽小巧&#xff0c;却对人们口腔清洁有一定作用&#xff0c;扬州卓韵酒店用品在这个领域表现优秀&#xff0c;下面我们就深入了解酒店一次性牙刷。 一次性牙刷的材质相当重要。常见的有…...

[人机交互]理解用户

一.解释什么是认知&#xff0c;以及它对交互设计的重要性 1.1什么是认知 认知是指与knowing相关的能力&#xff0c;行为和过程&#xff08;考填空&#xff09; -如何感知物理刺激&#xff1f;如注意、知觉等 -如何认识自我、他人以及环境&#xff1f;如意识、记忆等 -如何…...

css3伸缩盒模型第二章(侧轴相关)

css3伸缩盒模型第二章(侧轴相关) 侧轴对齐方式 侧轴对齐我们需要分两种情况&#xff0c;一种是多行&#xff0c;一种是单行&#xff0c;两种设置方式不同 属性&#xff1a;align-items 单行属性&#xff1a; align-content 多行 单行 align-items flex-start: 侧轴的起点对…...

【WPS】怎么解决“word的复制表格”粘贴到“excel的单元格”变多行单元格的问题

把 word文档复制表格到这个excel表格上面的话&#xff0c;会出现由单个单元格变成多行单元格的情况。 现在&#xff0c;就这个问题怎么解决&#xff0c;提出了一个方案&#xff0c;就是先查找是什么导致了这个换行&#xff0c;然后再将换行的这个字符进行一个整体的替换&#x…...

股指期货深度贴水是什么意思?

如果贴水的幅度特别大&#xff0c;比如股票指数是3000点&#xff0c;但股指期货的价格只有2800点&#xff0c;贴水了200点&#xff0c;这就叫“深度贴水”。简单来说&#xff0c;股指期货贴水就是指股指期货的价格低于其对应的现货指数价格。当这种贴水程度较大时&#xff0c;就…...

GCC编译器安装详细说明(举例arm-2013q3)

比如在官网GNU Arm Embedded Toolchain project files : GNU Arm Embedded Toolchain 下载了一个gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2 1 sudo tar -xvf gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2 解决了解压 在部署环境&#xff0c;在安装2…...

第十一届蓝桥杯 2020 C/C++组 蛇形填数

目录 题目&#xff1a; 题目描述: 题目链接&#xff1a; 思路&#xff1a; 思路详解&#xff1a; 代码&#xff1a; 代码详解&#xff1a; 题目&#xff1a; 题目描述: 题目链接&#xff1a; 蛇形填数 - 蓝桥云课 思路&#xff1a; 思路详解&#xff1a; 看图找规律…...

https://juejin.cn/editor/drafts/7262346366541070395

.Net Core从零学习搭建权限管理系统教程 推荐一组WPF自定义控件开源项目。 项目简介 这是基于WPF开发的&#xff0c;为开发人员提供了一组方便使用自定义组件&#xff0c;并提供了各种常用的示例。 包含组件&#xff1a;数据表格、属性列表、树形列表、选色器、单选框列表、…...

STL?string!!!

一、引言 在之前的文章中&#xff0c;我们一同学习了有关类和对象、模板、动态内存管理的相关知识&#xff0c;那么接下来一段时间我们将要趁热打铁&#xff0c;一起来手撕C库中最重要的一个库----STL中的一些容器&#xff0c;在手撕它们之前&#xff0c;我将先介绍一下对应的容…...

CentOS 7 安装指定版本 Docker 及镜像加速/配置优化攻略

摘要 本文详述 CentOS 7 系统下安装指定版本 Docker &#xff0c;涵盖镜像加速配置&#xff08;实测最快&#xff09;、存储位置优化、日志轮转等核心配置。 文章目录 一、安装指定版本Docker1.1 卸载旧版本&#xff08;如有&#xff09;1.2 安装依赖包1.3 添加Docker仓库&…...

域名别名(CNAME)解析及域名注册操作步骤

以虚拟主机为例&#xff0c;大多网站空间无独立ip&#xff0c;域名打开以别名解析为主&#xff0c;那域名别名&#xff08;CNAME&#xff09;如何解析呢&#xff1f;以下以新网为例&#xff0c;别名解析操作步骤&#xff1a; 1.登录域名管理界面&#xff0c;点击管理解析记录; …...

JVM内存模型深度解剖:分代策略、元空间与GC调优实战

堆 堆是Java虚拟机&#xff08;JVM&#xff09;内存管理的核心区域&#xff0c;其物理存储可能分散于不同内存页&#xff0c;但逻辑上被视为连续的线性空间。作为JVM启动时创建的第一个内存区域&#xff0c;堆承载着几乎所有的对象实例和数组对象&#xff08;极少数通过逃逸分…...

Unity_JK框架【1】 框架导入 对象池示例 (资源管理底层)

一、JK框架介绍 主要功能系统&#xff1a; 对象池系统&#xff1a;重复利用GameObject或普通class实例&#xff0c;并且支持设置对象池容量 事件系统&#xff1a;解耦工具&#xff0c;不需要持有引用来进行函数的调用 资源系统 Resources版本&#xff1a;关联对象池进行资源…...

JDK 发展历史及其版本特性

JDK&#xff08;Java Development Kit&#xff0c;Java开发工具包&#xff09;是用于开发Java应用程序的核心工具之一。它由Oracle&#xff08;最初由Sun Microsystems&#xff09;提供&#xff0c;包含了Java编译器、Java运行环境&#xff08;JRE&#xff09;、Java标准类库等…...

B站视频下载到电脑的方法总结

将B站&#xff08;哔哩哔哩&#xff09;视频下载到电脑的方法有多种&#xff0c;以下是几种常见且有效的方法&#xff0c;分为 官方工具 和 第三方工具 两类&#xff1a; 一、官方方法&#xff08;B站客户端或功能&#xff09; 哔哩哔哩客户端&#xff08;UWP/PC版&#xff09;…...

2025 后端自学UNIAPP【项目实战:旅游项目】2、安装下载引用前端UI框架:uview-plus

1、uview-plus官网地址&#xff0c;有详细介绍&#xff0c;感兴趣的可以深入了解学习 介绍 | uview-plus - 全面兼容nvue/鸿蒙/uni-app-x的uni-app生态框架 - uni-app UI框架 2、Hbuilder X 方式安装下载引入uview-plus ①进入该网址&#xff0c;点击 下载插件并导入Hbuild…...

Vue 的双向绑定原理,Vue2 和 Vue3 双向绑定原理的区别

Vue 的双向绑定原理&#xff0c;Vue2 和 Vue3 双向绑定原理的区别 Vue 的双向绑定&#xff08;Two-way Data Binding&#xff09;是其核心特性之一&#xff0c;其本质是通过数据劫持结合发布-订阅模式实现的。以下是 Vue2 和 Vue3 在双向绑定原理上的区别和演进&#xff1a; 文…...

RAG_Techniques:探索GitHub热门RAG技术开源项目

RAG_Techniques&#xff1a;探索GitHub热门RAG技术开源项目 引言项目概述RAG技术简介与重要性核心功能详解1. 分类清晰的技术体系2. 前沿技术解析3. 评估工具与方法 安装和使用教程应用场景和实际价值企业知识库和文档检索教育和研究辅助个性化内容推荐 结论 引言 在当今AI领域…...

Java高频面试之并发编程-12

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;详细说说java的内存模型 Java内存模型&#xff08;Java Memory Model, JMM&#xff09;是Java多线程编程的核心&#…...

多线程系列五:面试中常考的单例模式

1.设计模式 在了解单例模式之前我们先要了解设计模式&#xff1a; 设计模式是一种软性规定&#xff0c;遵守了设计模式&#xff0c;代码的下限就被兜住了&#xff0c;类似于棋谱&#xff0c;是大佬设计出来的&#xff0c;让小白程序员也能写出好的代码 设计模式有很多种&#x…...

音视频之H.265/HEVC编解码并处理

H.265/HEVC系列文章&#xff1a; 1、音视频之H.265/HEVC编码框架及编码视频格式 2、音视频之H.265码流分析及解析 3、音视频之H.265/HEVC预测编码 4、音视频之H.265/HEVC变换编码 5、音视频之H.265/HEVC量化 6、音视频之H.265/HEVC环路后处理 7、音视频之H.265/HEVC熵编…...

Python入门(一)

目录 一、Python数据类型 1.字面量 2.注释 3.变量 4.数据类型 二、 运算符 1.数据类型之间的相互转换 2 算数运算符 3、逻辑运算符 三、判断语句 if 四、循环 1、while循环 2、for循环 2.1 for...else... 五、格式化字符串 1.字符串 1.1创建字符串的方式&…...

2025年01月09日德美医疗前端面试

目录 vue2 的双向绑定的原理vue3 的双向绑定原理vue 的生命周期vue 子组件为何不能修改父组件的值js delete 删除数组的某一个值会怎么样vue 和 react 的 diff 算法什么是闭包原型链this指向 vue2 的双向绑定的原理 以下是 Vue 2 双向绑定的原理&#xff1a; 1. 核心概念 …...

02 mysql 管理(Windows版)

一、启动及关闭 MySQL 服务器 1.1 通过 “服务” 管理工具 winr打开运行&#xff0c;输入services.msc 找到MySQL80&#xff0c;这个是我们在安装mysql的时候给的服务的名称&#xff0c;具体见文章mysql 安装 右键选择启动或者停止。 1.2 通过命令提示符 1.2.1 关闭命令…...

开发搭载OneNet平台的物联网数据收发APP的设计与实现

一、开发环境与工具准备 工具安装 下载HBuilderX开发版(推荐使用开发版以避免插件兼容性问题)安装Node.js和npm(用于依赖管理及打包)配置Android Studio(本地打包需集成离线SDK)项目初始化 创建uni-app项目,选择“默认模板”或“空白模板”安装必要的UI库(如uView或Van…...

ntdll!LdrpInitializeProcess函数分析之Peb->Ldr和全局变量ntdll!PebLdr的关系

代码部分A&#xff1a; PEB_LDR_DATA PebLdr; //全局变量ntdll!PebLdr NTSTATUS LdrpInitializeProcess ( IN PCONTEXT Context OPTIONAL, IN PVOID SystemDllBase ) { 代码部分B&#xff1a; // // Figure out process name. // Teb NtCurrentTeb…...

如何开始使用 Blender:Blender 3D 初学者指南和简介 怎么下载格式模型

Blender 是一个强大的 3D 创作套件&#xff0c;为动画、视觉效果、艺术等提供了一系列功能。无论您是初学者还是经验丰富的艺术家&#xff0c;Blender 都提供了一个免费的开源平台来释放您的创造力。凭借其内置的视频序列编辑器&#xff0c;Blender 还提供基本的编辑功能&#…...

Nginx安全防护与HTTPS部署

目录 一、Nginx 概述 二、Nginx 核心安全配置 &#xff08;一&#xff09;编译安装 Nginx &#xff08;二&#xff09;隐藏版本号 &#xff08;三&#xff09;限制危险请求方法 &#xff08;四&#xff09;请求限制&#xff08;CC 攻击防御&#xff09; &#xff08;五&…...

HTTP 与 HTTPS 的深度剖析:差异、原理与应用场景

HTTP 与 HTTPS 的深度剖析&#xff1a;差异、原理与应用场景 在互联网的世界里&#xff0c;HTTP&#xff08;超文本传输协议&#xff09;和 HTTPS&#xff08;超文本传输安全协议&#xff09;是数据传输的 “高速公路”&#xff0c;它们承载着我们日常浏览网页、购物支付等各种…...

SMT贴片钢网精密设计与制造要点解析

内容概要 SMT贴片钢网作为电子组装工艺的核心载体&#xff0c;其设计与制造质量直接影响焊膏印刷精度及产品良率。本文系统梳理了钢网全生命周期中的15项关键技术指标&#xff0c;从材料选择、结构设计到工艺控制构建完整技术框架。核心要点涵盖激光切割精度的微米级调控、开口…...

算法每日一题 | 入门-顺序结构-三角形面积

三角形面积 题目描述 一个三角形的三边长分别是 a、b、c&#xff0c;那么它的面积为 p ( p − a ) ( p − b ) ( p − c ) \sqrt{p(p-a)(p-b)(p-c)} p(p−a)(p−b)(p−c) ​&#xff0c;其中 p 1 2 ( a b c ) p\frac{1}{2}(abc) p21​(abc) 。输入这三个数字&#xff0c;…...

Linux内核视角:线程同步与互斥的原理、实现与锁优化策略

Linux系列 文章目录 Linux系列前言一、前提知识二、线程互斥概念引入三、线程互斥3.1 什么是线程的互斥3.2 线程互斥的实现 四、锁的实现原理 前言 在前两篇文章中&#xff0c;我们已经对线程的相关概念及基本操作进行了深入介绍。在本篇中&#xff0c;我们将深入探讨编写多线…...

【区块链】Uniswap详细介绍

一、前言 本文将结合网上的资料和博主的理解&#xff0c;像大家详细介绍Uniswap&#xff0c;包括其核心概念、工作原理、版本演进、代币经济学以及风险点&#xff0c;适合想深入了解去中心化交易所&#xff08;DEX&#xff09;机制的用户。 二、Uniswap是什么 Uniswap 是一个…...

YOLOv8的Python基础--函数篇

1. 文件/目录操作相关函数 这些函数来自 os 和 shutil 模块&#xff1a; 函数/用法作用示例说明os.listdir(dir)列出目录下所有文件名os.listdir("./images")返回文件名列表&#xff08;不包含路径&#xff09;os.path.join()拼接路径os.path.join("dir"…...

vue源代码采用的设计模式分解

No.大剑师精品GIS教程推荐0地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】 1Openlayers 【入门教程】 - 【源代码示例 300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3MapboxGL【入门教程】 - 【源代码图文示例150】 4Cesium 【入门教程】…...

强化学习是AI Agent的进化引擎还是技术枷锁呢?

第一章 强化学习&#xff1a;Agent的“灵魂”觉醒之路 1.1 AlphaGo的启示&#xff1a;从规则到目标驱动的范式革命 2016年AlphaGo击败李世石的事件&#xff0c;标志着RL首次在复杂决策场景中展现其颠覆性价值。通过深度神经网络与RL的结合&#xff0c;AlphaGo无需依赖人类棋谱…...

python简易实现勒索病毒

python简易实现勒索病毒 1.首先介绍Crypto库1.1首先是对称加密1.2 非对称加密1.3 哈希 2.生成RSA密钥并保存3.文件加密4.文件解密1. 导入必要的模块2. 定义解密函数3. 设置私钥的密码4. 打开并读取文件5. 导入私钥6. 读取加密数据7. 解密会话密钥8. 创建 AES 解密器9. 解密数据…...

Nacos源码—4.Nacos集群高可用分析三

大纲 6.CAP原则与Raft协议 7.Nacos实现的Raft协议是如何写入数据的 8.Nacos实现的Raft协议是如何选举Leader节点的 9.Nacos实现的Raft协议是如何同步数据的 10.Nacos如何实现Raft协议的简版总结 6.CAP原则与Raft协议 (1)CAP分别指的是什么 (2)什么是分区以及容错 (3)为…...

AWS WebRTC如何实现拉流?内部是这样实现的

当我们通过手机上的app选择某一个Iot设备,例如,摄像头,想看实时视频的时候,aws都做了什么?最近在搞自研Iot项目,借机整理一下相关流程。 App通过 AWS SDK 发起拉流请求的内部机制是AWS Kinesis Video Streams (KVS) WebRTC 模式中一个非常关键的问题。 一、KVS WebRTC …...