Spring Boot 学习之路 -- 基础认知
前言
- 最近因为业务需要,被拉去研究后端的项目,代码框架基于 Spring Boot,对我来说完全小白,需要重新学习研究…
- 出于个人习惯,会以 Blog 文章的方式做一些记录,文章内容基本来源于「 Spring Boot 从入门到精通(明日科技) 」一书,做了一些整理,更易于个人理解和回顾查找,所以大家如果希望更系统性的学习,可以阅读此书(比较适合我这种新手)。
一、概述
Spring Boot 是在 Spring 的基础上发展而来的全新的开源框架。它是由 Pivotal 团队开发的。开发 Spring Boot 的主要动机是简化部署 Spring 应用程序的配置过程。也就是说,使用 Spring Boot 能够以更简单的、更灵活的方式开发 Spring 应用程序。
Spring Boot的主要特点如下:
▪️ Spring Boot 的代码非常少。Spring 的注解驱动编程避免了大量的配置工作,并且 Spring Boot 可以自动创建各种工厂类,程序开发人员直接通过依赖注入就可以获取各类对象。
▪️ Spring Boot 的配置非常简单。程序开发人员只需在 application.properties 或 application.yml 文件中编写一些配置项就可以影响整个项目。即使不编写任何配置,项目也可以采用一套默认配置正常启动。Spring Boot 支持使用 @Configuration 注解管理、维护配置类,让配置工作变得更灵活。
▪️ Spring Boot 可以自动部署。Spring Boot 自带 Tomcat 服务器,在项目启动的过程中可以自动完成所有资源的部署操作。
▪️ Spring Boot 易于单元测试。Spring Boot 自带 JUnit 单元测试框架,可以直接测试各个组件中的方法。
▪️ Spring Boot 集成了各种流行的第三方框架或软件。Spring Boot 提供了许多集成其他技术的依赖包,程序开发人员可以直接通过这些依赖包调用第三方框架或软件,例如 Redis、MyBatis、ActiveMQ 等。
▪️ Spring Boot 项目启动的速度很快。即使项目有庞大的依赖库,仍能在几秒之内完成部署和启动。
二、基础
因为注解在 Spring Boot 中发挥着至关重要的作用,所以为了能够快速地掌握 Spring Boot,须明确什么是注解和 Spring Boot 常用注解的功能及其标注位置。在 Spring Boot 容器中,存放着很多的 Bean。为此,须明确 Bean 是什么,并深入理解与其相关的两个过程:注入 Bean 和注册 Bean。在开发 Spring Boot 项目中,离不开“依赖”,我们须掌握如何为项目添加依赖。与此同时,还须掌握如何为 Spring Boot 项目中的程序元素命名。
2.1 注解
在程序开发的过程中,注解是无处不在的。但是,注解又不是必需的;换言之,在不使用注解的情况下,也能够开发程序。只不过,掌握注解能够帮助程序开发人员深入理解框架,进而提高程序开发的效率。那么,什么是注解呢?注解的作用又有哪些呢?
2.1.1 概念及其应用
在给出注解的概念之前,须明确什么是元数据。所谓元数据,指的是用于描述数据的数据。下面结合某个配置文件里的一行信息,举例说明什么是元数据。
<string name="app_name">AnnotionProject</string>
上述信息中的数据 “app_name” 是用于描述数据 AnnotionProject 的。也就是说,数据 “app_name” 就是元数据。那么,什么是注解呢?注解又被称作标注,是一种被加入源码的具有特殊语法的元数据。
需要特别说明的是:
- 注解仅仅是元数据,和业务逻辑无关。
- 虽然注解不是程序本身,但是可以对程序做出解释。
- 应用程序中的类、方法、变量、参数、包等程序元素都可以被注解。
理解了“什么是注解”后,再来了解一下在应用程序中注解的应用体现在哪些方面:
- 在编译时进行格式检查。例如,如果被 @Override 标记的方法不是父类的某个方法,编译器就会报错。
- 减少配置。依据代码的依赖性,使用注解替代配置文件。
- 减少重复工作。在程序开发的过程中,通过注解减少对某个方法的调用次数。
2.1.2 常用注解及其标注位置
Spring Boot 是一个支持海量注解的框架:
注解 | 标注位置 | 功能 |
---|---|---|
@autowired | 成员变量 | 自动注入依赖 |
@Bean | 方法 | @Bean 用于注册 Bean,当 @Bean 标记方法时,等价于在 XML 中配置 Bean |
@Component | 类 | 用于注册组件。当不清楚注册类属于哪个模块时就用这个注释 |
@ComponentScan | 类 | 开启组件扫描器 |
@Configuration | 类 | 声明配置类 |
@ConfigurationProperties | 类 | 用于加载额外的 properties 配置文件 |
@Controller | 类 | 声明控制器类 |
@ControllerAdvice | 类 | 可用于声明全局异常处理类和全局数据处理类 |
@EnableAutoConfiguration | 类 | 开启项目的自动配置功能 |
@ExceptionHandler | 方法 | 用于声明处理全局异常的方法 |
@Import | 类 | 用于导入一个或者多个 @Configuration 注解标注的类 |
@ImportResource | 类 | 用于加载 XML 配置文件 |
@PathVariable | 方法参数 | 让方法参数从 URL 中的占位符中取值 |
@Qualifier | 成员变量 | 与 @Autowired 配合使用,当 Spring 容器中有多个类型相同的 Bean 时,可以用 @Qualifier(“name”) 来指定注入哪个名称的 Bean |
@RequestMapping | 方法 | 指定方法可以处理哪些 URL 请求 |
@RequestParam | 方法参数 | 让方法参数从 URL 参数中取值 |
@Resource | 成员变量 | 与 @Autowired 功能类似,但是有 name 和 type 两个参数,可根据 Spring 配置的 Bean 的名称进行注入 |
@ResponseBody | 方法 | 表示方法的返回结果直接写入 HTTP response body 中。如果返回值是字符串,则直接在网页上显示该字符串 |
@RestController | 类 | 相当于 @Controller 和 @ResponseBody 的合集,表示在这个控制器下的所有方法都被 @ResponseBody 标注 |
@Service | 服务的实现类 | 用于声明服务的实现类 |
@SpringBootApplication | 主类 | 用于声明项目主类 |
@Value | 成员变量 | 动态注入,支持 " #{ } " 与 " ${ } " 表达式 |
这些注解的编码位置是非常灵活的。当注解用于标注类、成员变量和方法时,注解的编码位置既可以在成员变量的上边,例如:
@Autowired
private String name;
又可以在成员变量的左边,例如:
@Autowired private String name;
在 Spring Boot 的常用注解中,需特别说明的是,使用 @RequestParam 能够标注方法中的参数。例如:
@RequestMapping("/user")
@ResponseBody
public String getUser(@RequestParam Integer id) {
return "success";
}
2.1.3 使用@SpringBootApplication标注启动类
使用注解能够启动一个 Spring Boot 项目,这是因为在每一个 Spring Boot 项目中都有一个启动类(主类),并且启动类必须被 @SpringBootApplication 注解标注,进而能够调用用于启动一个 Spring Boot 项目的 SpringApplication.run() 方法。
如下:
package com.spark.springbootlearning;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootLearningApplication {public static void main(String[] args) {SpringApplication.run(SpringBootLearningApplication.class, args);}}
@SpringBootApplication 注解虽然重要,但使用起来非常简单,因为这个注解是由多个功能强大的注解整合而成的。
打开 @SpringBootApplication 注解的源码可以看到它被很多其他注解标注,其中最核心的 3 个注解分别是:
- SpringBootConfiguration 注解:让项目采用基于 Java 注解的配置方式,而不是传统的 XML 文件配置。当然,如果程序开发人员写了传统的 XML 配置文件,Spring Boot 也是能够读取这些 XML 文件并识别里面的内容的。
- @EnableAutoConfiguration 注解:开启自动配置。这样 Spring Boot 在启动时就可以自动加载所有配置文件和配置类了。
- @ComponentScan 注解:启用组件扫描器。这样项目才能自动发现并创建各个组件的 Bean,包括 Web 控制器(@Controller)、服务(@Service)、配置类(@Configuration)和其他组件(@Component)。
注意:
一个项目可以有多个启动类,但这样的代码毫无意义。一个项目应该只使用一次@ SpringBootApplication 注解。
@SpringBootApplication 有一个使用要求:只能扫描底层包及其子包中的代码。底层包就是启动类所在的包。如果启动类在 com.spark.springbootlearning 包下,其他类应该写在 com.spark.springbootlearning 包或其子包中,否则无法被扫描器找到,就等同于无效代码。例如在图3.1和图3.2中,Controller类所在的位置可以被扫描到。而在图3.3和图3.4中,Controller类的位置就无法被扫描到了。
2.2 Bean 的注册和获取
Bean 指的是由 Spring Boot 容器管理的对象。Bean 是根据 Spring Boot 配置文件中的数据信息予以创建的。如果把 Spring Boot 容器看作是一个大工厂,那么 Bean 就相当于这个工厂生成的产品。
2.2.1 Bean 与依赖注入
在明确了什么是 Bean 后,还需要明确另外一个非常重要的概念:依赖注入。
在面向对象程序设计中,对象和对象之间存在一种叫作“依赖”的关系。简单来说,依赖关系就是在一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类的对象。
例如,在一个 B 类对象中,有一个 A 类的对象 a,那么就可以说 B 类的对象依赖于对象 a。而依赖注入就是基于这种“依赖关系”而产生的。
Spring Boot 在创建一个对象的过程中,会根据“依赖关系”,把这个对象依赖的对象注入其中,这就是所谓的“依赖注入”。
掌握了 Bean 和依赖注入的概念后,再结合下图理解两个过程:
- 「 Bean 的注册 」:Spring Boot 能够自动寻找程序开发人员已经创建好的 Bean,并将其保存在 Spring Boot 容器中,这个过程被称作 Bean 的注册。
- 「 Bean 的注入 」:把 Spring Boot 容器中的 Bean 赋值给某个尚未被赋值的成员变量,这个过程被称作 Bean 的注入。
当 Spring Boot 项目被启动时,Spring Boot 首先会自动扫描所有的组件,然后注册所有的 Bean,最后把这些 Bean 注入各自的使用场景当中。下面通过一个实例,演示「 注册 Bean 」和「 注入 Bean 」的这两个过程。
- 创建用于注册 Bean 的组件类:BeanComponent
BeanComponent 类被 @Component 标注,表示这个类是一个组件类。类中只有一个 name() 方法,并且被 @Bean 标注,表示这个方法返回的对象被注册成了 Bean,并将其放到 Spring Boot 容器中。
- 创建 BeanTestController 控制器类
BeanTestController 类被 @RestController 标注,表示这个类是一个负责页面跳转的控制器,会直接返字符串结果。类中:
- name 属性被 @Autowired 标注,表示这个属性的值由 Spring Boot 注入。
- showName() 方法被 @RequestMapping(“/bean”) 标注,表示该方法映射“/bean”地址,并将 name 的值展示在页面中。
- 启动项目,打开浏览器,访问 http://127.0.0.1:8080/bean 地址,可以看到下图所示的结果:
页面中显示 “BeanComponent”,但 BeanTestController 类中没有出现任何 “BeanComponent” 的字样,这个值是哪来的呢?“BeanComponent” 这个值出现在 BeanComponent 类的 name() 方法的返回值中。当 Spring Boot 项目被启动时,扫描器发现了 BeanComponent 类,并在该类下发现了被 @Bean 标注的方法,于是把该方法返回的对象注册成 Bean,再放到 Spring Boot 容器中。与此同时,扫描器也发现了 BeanTestController 类,发现这个类有一个 name 属性需要被注入值,Spring Boot 便在 Spring Boot 容器中查找有没有类型相同、名称匹配的 Bean,于是就找到了 name() 方法返回的字符串“BeanComponent”,便将 “BeanComponent” 赋给了 name 属性。当前端发来请求时,showName() 方法便将 name 的值(也就是“BeanComponent”)展示在了网页中。这就是一个「 注册 Bean 」和「 注入 Bean 」的例子。
2.2.2 注册 Bean
注册 Bean 需要用到 @Bean 注解,该注解用于标注方法,表示方法的返回值是一个即将进入 SpringBoot 容器中的 Bean。下面介绍 @Bean 注解的具体用法。
📄 1. 让 Spring Boot 发现 @Bean
如果想让 @Bean 注解生效,那么被标注的方法所在的类必须能够被 Spring Boot 的组件扫描器扫描到。
以下几个注解都可以让被标注的方法所在的类被扫描到:
注解 | 说明 |
---|---|
@Configuration | 声明配置类 |
@Controller | 声明控制器类 |
@Service | 声明服务接口或类 |
@Repository | 声明数据仓库 |
@Component | 如果不知道类属于什么模块,就用这个注解将类声明成组件。推荐使用此注解 |
如果不使用上面这 5 个注解,那么也可以用 @Import 注解将 @Bean 所在类的主动注册给 Spring Boot。
例如,我们修改刚才的代码,删除 BeanComponent 类上的 @Component 注解,代码如下:
在 Spring Boot 项目的启动类中,通过使用
@Import({com.mr.component.BeanComponent.class})
声明启动类,让项目启动时自动导入 BeanComponent 类,代码如下:
这样,当 Spring Boot 项目被启动时,BeanComponent 类中的 @Bean 也可以被注册到 Spring Boot 容器中(这里就不运行了,你可以自己测试)。
如果想要导入多个指定的类,@Import 的语法如下(注意圆括号和大括号的位置):
@Import({A.class, B.class, C.class})
📄 2. @Bean的使用方法
@Bean 注解有很多属性,其核心源码如下:
public @interface Bean {@AliasFor("name")String[] value() default {};@AliasFor("value")String[] name() default {};boolean autowireCandidate() default true;String initMethod() default "";String destroyMethod() default "(inferred)";
}
下面分别介绍这几个属性的用法:
- value 和 name 这两个属性的作用是一样的:就是给 Bean 起别名,让 Spring Boot 可以区分多个类型相同的 Bean。给 Bean起别名的语法如下:
@Bean("goudan")
@Bean(value = "goudan")
@Bean(name = "goudan")
@Bean(name = {"goudan", "GouDan", "Golden"}) // 同时给一个 Bean 起多个别名
如果没有给 Bean 起任何别名的话,那么 @Bean 注解会默认将方法名作为别名,例如:
@Bean
public String name() {
return "Marco";
}
上面代码等同于:
@Bean(name = "name")
public String name() {
return "Marco";
}
- autowireCandidate 属性:表示 Bean 是否采用默认的自动匹配机制,默认值为 true,如果将其赋值为 false,这个 Bean 就不会被默认的自动匹配机制匹配到,只能通过「使用别名的方式」匹配到。
比如,我们修改刚才的例子,代码如下:
BeanComponent 类中创建了两个方法,返回值类型均为 String。otherName() 方法定义了别名,并且 autowireCandidate 的值为 false,表示 Spring 在匹配 Bean 时会自动忽略 otherName() 方法的返回值。
下面再来看一下注入的代码。修改 BeanTestController 控制器类,代码如下:
BeanTestController 类定义了一个 name 属性,该属性使用 @Resource 标注,表示这个属性由 Spring 自动匹配并注入值。启动项目,打开浏览器访问 http://127.0.0.1:8080/bean 地址,看一下 name 被注入的值是什么:
name 的值为 “BeanComponent”,即使 Spring 容器中有两个 String 类型的 Bean,但值为 “Marco” 的 Bean 拒绝自动匹配机制,所以 name 只能得到 “BeanComponent” 这个值。
如果想要得到 “Marco” 这个 Bean,就需要在注入时指定 Bean 的别名。例如使用 @Resource 注解读取别名为 “In” 的 Bean,关键代码如下:
这样,name 取的值就是别名为 “In” 的 Bean 的值。重启 Spring Boot 项目,并且重新访问地址 http://127.0.0.1:8080/bean 后,就可以看到网页上显示的值变成了 “Marco”,效果如下:
- initMethod 属性:用于指定 Bean 初始化时会调用什么方法。
- destroyMethod 属性:用于指定 Bean 被 Spring 销毁时会调用什么方法,两个属性的值均为 Bean 对象的方法名。
2.2.3 获取 Bean
获取 Bean 就是在类中创建一个属性(可以是 private 属性),通过为属性添加注解,让 Spring Boot 为这个属性注入 Bean。
可以获取 Bean 的注解有3个:@Autowired、@Resouce 和 @Value。
这 3 个注解只能在可以被扫描到的类中使用。下面分别介绍这 3 个注解的用法。
📄 @Autowired
@Autowired 注解可以自动到 Spring 容器中寻找名称相同或类型相同的 Bean。例如,注册 Bean 的方法为:
@Bean
public String author() {
return "Marco";
}
获取这个 Bean 的代码可以写成:
@Autowired
String author;
@Autowired 可以自动匹配与属性同名(即别名为 “author”)的 Bean。如果匹配不到同名的 Bean,@Autowired 可以自动匹配类型相同的 Bean。例如,注册方法不变,获取 Bean 的代码为:
@Autowired
String name;
即使这么写,name 也可以获得 “Marco” 这个值,因为两者数据类型是相同的。
但要注意,当 Spring Boot 容器中仅有一个该类型的 Bean 时,@Autowired 才能匹配成功。如果存在多个该类型的 Bean,Spring 就不知道应该匹配哪个 Bean 了,项目就会抛出异常。例如,注册 Bean 的方法如下:
@Bean
public String author() {
return "Marco";
}

@Bean
public String dev() {
return "Superman";
}
现在容器中有两个 String 类型的 Bean,然后获取 Bean 的代码为:
@Autowired
String name;
启动项目后会抛出如下异常日志:
***************************
APPLICATION FAILED TO START
***************************Description:Field name in com.spark.springbootlearning.controller.BeanTestController required a single bean, but 2 were found:- author: defined by method 'author' in class path resource [com/spark/springbootlearning/component/BeanComponent.class]- dev: defined by method 'dev' in class path resource [com/spark/springbootlearning/component/BeanComponent.class]This may be due to missing parameter name information
IDEA 代码也会有波浪线报错提示:
这个异常日志的意思是:程序需要自动匹配一个独立的 Bean,却找到了两个符合条件的 Bean。其中,一个 Bean 的别名叫“author”,另一个 Bean 的别名叫“dev”。程序因为不知道哪个 Bean 是当前需要的,所以就停止了。
在这种因同时存在多个 Bean 而无法自动匹配的情况下,就需要指定 Bean 的别名以获取 Bean。
指定别名有两种方式:
- 将类属性名改成 Bean 的别名。如果 Bean 的别名叫 “author”,@Autowired 标注的属性名也叫 “author”。
- 使用 @Qualifier 注解。@Qualifier 注解有一个 value 属性,用于指定要获取的 Bean 的别名。可以与 @Autowired 配套使用。例如,获取别名为 “dev” 的 Bean,代码如下:
@Autowired
@Qualifier("dev")
String name;
📄 @Resource
@Resource 注解的功能与 @Autowired 类似:@Resouce 注解自带 name 属性,可直接指定 Bean 的别名。其中,name 属性的默认值为空字符串,表示自动将被标注的属性名作为 Bean 的别名。
例如,获取别名为 “author” 的 Bean,可以有 3 种写法:
第一种写法:
@Resource(name="author")
String name;
第二种写法:
@Resource
String author; // 属性名就叫 author
第三种写法:虽然可以执行,实际与第一种写法是一样的,不推荐这样写
@Resource(name="")
String author;
注意:
如果使用 @Autowired 注入 Object 类型的 Bean 时,抛出了 org.springframework.beans.factory. NoUniqueBeanDefinitionException:No qualifying bean of type ‘java.lang.Object’ available 异常,就将 @Autowired 换成 @Resource。
📄 @Value
@Value 注解可以动态地向属性注入值。@Value 有3种语法,分别是:
- 注入常量值。
下面的语法会让 name 的值等于 “author” 这个字符串,例如:
@Value("author")
String name;
- 注入 Bean。
使用 “#{Bean别名}” 格式可以注入指定别名的 Bean,其效果类似于 @Resource(name=“Bean别名”),例如:
@Value("#{author}")
String name;
- 注入配置文件中配置信息的值。
使用“${配置项}”格式可以注入 application.properties 文件中指定名称的配置信息的值,例如:
@Value("${author}")
String name;
注意:
如果配置文件中没有该项则会抛出 BeanCreationException 异常。
2.3 为Spring Boot项目添加依赖
在 Spring Boot 项目开发的过程中,有些依赖需要程序开发人员手动添加。本节将对如何手动为 Maven 项目添加依赖进行讲解。
2.3.1 在 pom.xml 文件中添加依赖
pom.xml 是Maven构建项目的核心配置文件,程序开发人员可以在此文件中为项目添加新的依赖,新的依赖将被添加到 <dependencies> 标签的子标签中,添加依赖的格式如下:
<dependency>
<groupId>所属团队</groupId>
<artifactId>项目ID</artifactId>
<version>版本号</version>
<scope>使用范围(可选)</scope>
</dependency>
注意:
在 pom.xml 文件中,<dependency> 标签是 <dependencies> 标签的子标签。
例如,Spring Boot 项目自带的 Web 依赖和 JUnit 单元测试依赖在 pom.xml 中填写的位置如图所示。
程序开发人员只需要仿照这种格式在 标签内部添加其他依赖,然后保存 pom.xml 文件,Maven 就会自动下载依赖中的 jar 文件并自动引入项目中。
2.3.2 如何查找依赖的版本号
如果程序开发人员不知道依赖的 ID 和版本,可以到 MVNrepository 或阿里云云效 Maven 中去查找。
- MVNrepository 的官网地址为 https://mvnrepository.com/ ,查询结果如下图所示:
- 阿里云云效 Maven 虽然不会直接显示 XML 文本,但可以看到 groupId、artifactId 和 version 这3个值,效果如下图所示:
相关文章:

Spring Boot 学习之路 -- 基础认知
前言 最近因为业务需要,被拉去研究后端的项目,代码框架基于 Spring Boot,对我来说完全小白,需要重新学习研究…出于个人习惯,会以 Blog 文章的方式做一些记录,文章内容基本来源于「 Spring Boot 从入门到精…...

JavaScript --json格式字符串和对象的转化
json字符串解析成对象 : var obj JSON.parse(str) 对象转化成字符串:var str1 JSON.stringify(obj1) <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Com…...

LabVIEW提高开发效率技巧----采用并行任务提高性能
在复杂的LabVIEW开发项目中,合理利用并行任务可以显著提高系统的整体性能和响应速度。并行编程是一种强大的技术手段,尤其适用于实时控制、数据采集以及多任务处理等场景。LabVIEW的数据流编程模型天然支持并行任务的执行,结合多核处理器的硬…...

裸土检测算法实际应用、裸土覆盖检测算法、裸土检测算法
裸土检测算法主要用于环境保护、农业管理、城市规划和土地管理等领域,通过图像识别技术来检测和识别地表上的裸露土壤。这种技术可以帮助管理者实时监控裸土面积,及时采取措施,防止水土流失、环境污染和生态退化。 一、技术实现 裸土检测算…...

深入剖析链表反转:多语言实现与高级语法特性20240924
深入剖析链表反转:多语言实现与高级语法特性 引言 在数据结构与算法的学习中,链表是基础结构之一,尤其在动态内存分配和操作中体现了它的重要性。今天,我们将通过反转单链表这一经典算法题,从不同编程语言的角度进行…...

【数据结构初阶】链式二叉树接口实现超详解
文章目录 1. 节点定义2. 前中后序遍历2. 1 遍历规则2. 2 遍历实现2. 3 结点个数2. 3. 1 二叉树节点个数2. 3. 2 二叉树叶子节点个数2. 3. 3 二叉树第k层节点个数 2. 4 二叉树查找值为x的节点2. 5 二叉树层序遍历2. 6 判断二叉树是否是完全二叉树 3. 二叉树性质 1. 节点定义 用…...

力扣189 轮转数组 Java版本
文章目录 题目描述代码 题目描述 给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4…...

RMAN异机恢复数据库记录
场景:数据库服务器宕机,无法恢复 处理:使用备份资料进行异地恢复 1.此处环境为同平台、同版本(操作系统版本可以不同,但数据库版本需相同),源机器和目标机器具有相同的目录结构。 2.目标机器只…...

JVM 调优篇7 调优案例4- 线程溢出
一 线程溢出 1.1 报错信息 每个 Java 线程都需要占用一定的内存空间,当 JVM 向底层操作系统请求创建一个新的 native 线程时,如果没有足够的资源分配就会报此类错误。报错信息:java.lang.outofmemoryError:unable to create new Native Thr…...

C++类与对象(三)
目录 1.再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit关键字 2.STATIC成员 2.1 概念 2.2 特性 3.C中成员初始化的新玩法 4.友元 4.1 友元函数 4.2 友元类 5.内部类 6.再次理解封装 7.再次理解面向对象 本次内容大纲: 1.再谈构造函数 …...

云栖实录 | 阿里云 OpenLake 解决方案重磅发布:多模态数据统一纳管、引擎平权联合计算、数据共享统一读写
新一轮人工智能浪潮正在重塑世界,以生成式 AI 为代表的技术快速应用,推动了数据与智能的深化融合,同时也给数据基础设施带来了全新的变革与挑战。面向 AI 时代的数据基础设施如何构建?底层数据平台架构在 AI 时代如何演进…...

《线性代数》学渣笔记
文章目录 1 行列式1.1 克拉默法则1.2 基本性质1.3 余子式 M i j M_{ij} Mij1.4 代数余子式 A i j ( − 1 ) i j ⋅ M i j A_{ij} (-1)^{ij} \cdot M_{ij} Aij(−1)ij⋅Mij1.5 具体型行列式计算(化为基本型)1.5.1 主对角线行列式:主…...

对网页聊天项目进行性能测试, 使用JMeter对于基于WebSocket开发的webChat项目的聊天功能进行测试
登录功能 包括接口的设置和csv文件配置 这里csv文件就是使用xlsx保存数据, 然后在浏览器找个网址转成csv文件 注册功能 这里因为需要每次注册的账号不能相同, 所以用了时间函数来当用户名, 保证尽可能的给正确的注册数据, 时间函数使用方法如下 这里输入分钟, 秒…...

《程序猿之设计模式实战 · 适配器模式》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...

Elasticsearch案例
目录 一、创建索引 二、准备数据 三、环境搭建 (1)环境搭建 (2)创建实体类 (3)实现Repository接口 四、实现自动补全功能 五、实现高亮搜索关键字功能 (1)在repository接口中…...

SpringBoot 项目如何使用 pageHelper 做分页处理 (含两种依赖方式)
分页是常见大型项目都需要的一个功能,PageHelper是一个非常流行的MyBatis分页插件,它支持多数据库分页,无需修改SQL语句即可实现分页功能。 本文在最后展示了两种依赖验证的结果。 文章目录 一、第一种依赖方式二、第二种依赖方式三、创建数…...

GSR关键词排名系统是针对谷歌seo的吗?
是的,GSR关键词排名系统专门针对谷歌SEO,具体通过外部优化手段快速提升关键词排名。不同于传统的SEO策略,GSR系统并不依赖于对网站内容的调整或内部优化,完全通过站外操作实现效果。这意味着,用户不需要花费精力在网站…...

HarmonyOS Next开发----使用XComponent自定义绘制
XComponent组件作为一种绘制组件,通常用于满足用户复杂的自定义绘制需求,其主要有两种类型"surface和component。对于surface类型可以将相关数据传入XComponent单独拥有的NativeWindow来渲染画面。 由于上层UI是采用arkTS开发,那么想要…...

什么是电商云手机?可以用来干什么?
随着电商行业的迅速发展,云手机作为一种创新工具正逐渐进入出海电商领域。专为外贸市场量身定制的出海电商云手机,已经成为许多外贸企业和出海电商卖家的必备。本文将详细介绍电商云手机是什么以及可以用来做什么。 与国内云手机偏向于游戏场景不同&…...

Python 2 和 Python 3的差异
Python 2 和 Python 3 之间有许多差异,Python 3 是 Python 语言的更新版本,目的是解决 Python 2 中的一些设计缺陷,并引入更现代的编程方式。以下是 Python 2 和 Python 3 之间的一些主要区别: 文章目录 1. print 语句2. 整除行为…...

Leetcode 第 139 场双周赛题解
Leetcode 第 139 场双周赛题解 Leetcode 第 139 场双周赛题解题目1:3285. 找到稳定山的下标思路代码复杂度分析 题目2:3286. 穿越网格图的安全路径思路代码复杂度分析 题目3:3287. 求出数组中最大序列值思路代码复杂度分析 题目4:…...

spring 注解 - @NotEmpty - 确保被注解的字段不为空,而且也不是空白(即不是空字符串、不是只包含空格的字符串)
NotEmpty 是 Bean Validation API 提供的注解之一,用于确保被注解的字段不为空。它检查字符串不仅不是 null,而且也不是空白(即不是空字符串、不是只包含空格的字符串)。 这个注解通常用在 Java 应用程序中,特别是在处…...

深入理解华为仓颉语言的数值类型
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在编程过程中,数据处理是开发者必须掌握的基本技能之一。无论是开发应用程序还是进行算法设计,了解不同数据类型的特性和用途都至关重要。本文将深入探讨华为仓颉语言中的基本数…...

WPF 的TreeView的TreeViewItem下动态生成TreeViewItem
树形结构仅部分需要动态生成TreeViewItem的可以参考本文。 xaml页面 <TreeView MinWidth"220" ><TreeViewItem Header"功能列表" ItemsSource"{Binding Functions}"><TreeViewItem.ItemTemplate><HierarchicalDataTempla…...

使用Go语言的互斥锁(Mutex)解决并发问题
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在并发编程中,由于存在竞争条件和数据竞争,我们需要将某些代码片段设定为临界区,并使用互斥锁(Mutex)等同步原语来保护这些临界区。本文将详细介绍Go语言标准库中Mutex的使用方法,以及如何利用它来解决实际…...

Android平台Unity3D下如何同时播放多路RTMP|RTSP流?
技术背景 好多开发者,提到希望在Unity的Android头显终端,播放2路以上RTMP或RTSP流,在设备性能一般的情况下,对Unity下的RTMP|RTSP播放器提出了更高的要求。实际上,我们在前几年发布Unity下直播播放模块的时候…...

网络:TCP协议-报头字段
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》《网络》 文章目录 前言一、TCP协议格式16位源端口号 和 16位目的端口号4位首部长度16位窗口大小32位序号 和 32位确认序号6种标记位 和 16位紧急指针 总结 前言 本文是我对于TCP协…...

JAVA基础:HashMap底层数组容量控制,TreeMap底层存取机制,位运算符,原码反码补码
List常用实现类 List集合常用的实现类有3个 , ArrayList , LinkedList , Vector ArrayList 类似于我们之前的ArrayBox 底层使用数组存储元素, 插入删除的效率低,检索的效率高 当底层数组存储容量不足时,会进行扩容,…...

【Redis】Redis 缓存设计:抗住百万并发量的最佳实践
目录 1. Redis 缓存设计原则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.2.3 侧写缓存 3. Redis 架构设计3.1 单机 vs 集群3.2 Redis 集群示例架构 4. 性能…...

【hot100-java】【缺失的第一个正数】
R9-普通数组篇 class Solution {public int firstMissingPositive(int[] nums) {int nnums.length;for (int i0;i<n;i){while(nums[i]>0&&nums[i]<n&&nums[nums[i]-1]!nums[i]){//交换nums[i]和nums[nums[i]-1]int temp nums[nums[i]-1];nums[nums[i]…...