Spring Boot 框架官方文档:
查看 Spring Boot 版本新特性:github.com/spring-proj…
1. Spring 能做什么?
Spring 的生态覆盖:
- Web 开发
- 数据访问
- 安全控制
- 分布式
- 消息服务
- 移动开发
- 批处理
- ...
2. Spring Boot 为什么这么火?
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". Most Spring Boot applications need minimal Spring configuration.
Spring Boot 能快速创建出独立的、可直接运行的 Spring 应用程序。
大多数的 Spring Boot 应用只需要最少的 Spring 配置。
2.1 Spring Boot 的优点
Spring Boot 是整合 Spring 技术栈的一站式框架、是简化 Spring 技术栈的快速开发脚手架!
- Create stand-alone Spring applications
- 创建独立的 Spring 应用
- Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
- 内嵌 web 服务器
- Provide opinionated 'starter' dependencies to simplify your build configuration
- 提供自动
starter
依赖以简化构建配置
- 提供自动
- Automatically configure Spring and 3rd party libraries whenever possible
- 自动配置 Spring 以及第三方功能
- Provide production-ready features such as metrics, health checks, and externalized configuration
- 提供生产级别的监控、健康检查以及外部配置
- Absolutely no code generation and no requirement for XML configuration
- 无代码生成,无需编写 XML
2.2 从设计理念谈起
要说到 Spring Boot 为什么这么火,就必须得聊聊 Spring Boot 的设计理念,正是此设计理念奠基了 Spring Boot 开发设计的基准,让 Spring Boot 走到了今天。
那 Spring Boot 的设计理念是什么呢?它就是约定优于配置(convention over configuration)。
约定优于配置并不是一个新概念,它是一种软件设计范式,很早就应用在软件架构设计中,它的作用是减少软件开发人员需做决定的数量,获得简单的好处,而又不失灵活性。
只是 Spring Boot 让这个设计理念上升了一个层次,Spring Boot 不止在某个功能上实现此设计理念,而是整个软件体系都在践行约定优于配置。
Spring Boot 体系将约定优于配置的思想展现得淋淋尽致,小到配置文件,中间件的默认配置,大到内置容器、生态中的各种 Starters 无不遵循此设计规则。
Spring Boot Jpa
80% 大部分查询功能都以约定的方式给与提供,另外 20% 复杂的场景,提供另外的技术手段来解决,典型的约定优于配置的实现。
Spring Boot Starter
,在项目启动的时候,根据约定信息对组件进行加载、初始化。因此项目中引入了对于的 Starter 之后,就可以到达开箱即用的效果。
甚至 Spring Cloud
的设计,也借鉴了约定优于配置的思想,很多组件都是在启动时,默认提供了其相关的功能,可以让我们的使用到达很少配置或者零配置。
2.3 Spring Boot 的 Starter 机制
Spring Boot Starter 是 Spring Boot 的 星辰大海。
正是因为丰富的 Spring Boot Starter ,让 Spring Boot 征服了使用各个开源软件的开发者,只要 Spring Boot Starter 指向哪个开源软件,就会让某个开源软件变得异常好用。
那什么是 Spring Boot Starter 呢?
在 Spring Boot 中,Starter 是为快速应用开发提供“一站式服务”的依赖(Dependency)。Starter 使得开发人员在开始编写新的模块时不需要拷贝样板式的配置文件、编写样板式的代码,只需要提供最简单的配置即可开始编程。
Spring Boot Starter 有两个核心组件:自动配置代码和提供自动配置模块及其它有用的依赖。也就意味着当我们项目中引入某个 Starter ,即拥有了此软件的默认使用能力,除非我们需要特定的配置,一般情况下我仅需要少量的配置或者不配置即可使用组件对应的功能。
Spring Boot 由众多 Starter 组成,随着版本的推移 Starter 家族成员也与日俱增。在传统 Maven 项目中通常将一些层、组件拆分为模块来管理,以便相互依赖复用,在 Spring Boot 项目中我们则可以创建自定义 Spring Boot Starter 来达成该目的。
Spring Boot Starter 统一了使用不同软件的编程体验
在没有使用 Spring Boot Starter 之前,我们需要按照每个开源软件的特性,将对应的组件包集成到我们的开发项目中,因为每个组件的设计理念和开发团队都不一致,因此会有很多不同的调用风格在我们的项目中。
Spring Boot 强大到很多技术社区都主动提供了对应的 Starter 组件,比如 MyBatis 、Apache Camel、Apache CXF 等等。随着 Spring Boot 的发展 Starter 组件会越来越多。
Spring Boot 非常强大的原因之一就是提供了大量的 Spring Boot Starter ,如此多的“开箱即用” 的依赖模块,让我们在日常开发中“拿来即用”,以便更加快速和高效专注于业务开发。
2.4 Spring Boot 的豪华开发团队
我们经常会看到在介绍 Spring Boot 的时候有这么一句:Spring Boot 是由 Pivotal 团队提供的全新框架。由此我们得知 Spring Boot 是由 Pivotal 团队所研发,那么 Pivotal 团队到底是一个什么样的团队呢?其实这里的 Pivotal 团队是指 Pivotal 公司。
Pivotal 公司介绍:致力于“改变世界构造软件的方式(We are transforming how the world builds software)”,提供云原生应用开发 PaaS 平台及服务,帮助企业客户采用敏捷软件开发方法论,从而提高软件开发人员工作效率、减少运维成本,实现数字化转型、IT 创新,并最终实现业务创新。
Pivotal 公司可谓是大牛云集,公司研发的产品有: Spring 以及衍生框架、缓存中间件 Redis、消息队列框架 RabbitMQ、数据引擎产品 Greenplum,还有 Tomcat、Groovy 里的一些顶级开发者,DevOps 理论的提出者都在这个公司。
2016 年风靡全球的云原生理念亦是 Pivotal 公司提出,美国硅谷著名的精益化创业书籍的作者 Eric Ries 也加入了 Pivotal公司。Spring Boot 为什么如此的优秀,正是因为背后有这些全球的顶级开发者。
Pivotal 公司的背后其实是一场商业并购大片,有很多著名的公司在其身后,戴尔、Spring、EMC、VMware 等等,详情大家开源看这篇文章:《是时候给大家介绍 Spring Boot/Cloud 背后豪华的研发团队了》。
2.5 有个好干爹
Spring Boot 的干爹是谁呢?毫无疑问就是 Spring 了。
Spring Boot 完全依赖 Spring 来开发,发明 Spring Boot 也是为了让大家更好的使用 Spring,而不是消灭 Spring ,所以说没有 Spring 这个干爹,就没有 Spring Boot 。
当然 Spring Boot 不仅是基于 Spring 开发这么简单,Spring Boot 完全继承了 Spring 干爹的声誉,说实话如果没有 Spring 这个老干爹十多年来打拼下来的天气,哪有 Spring Boot 今天来的风光。
2002 年的时候, Rod Johnson 可能也没有想到自己开创的一个小开源软件,可以发展到今天这么辉煌的一刻。到了今天,如果一个 Java 程序员说自己不知道 Spring ,那估计会把他当作外星人吧。
Spirng 当时以 IoC 和 Aop 开始发家,一开始的目标只是想干掉 EJB 这个庞然大物,但是随着时间的发展,Spring 开始了一路的逆袭之路,在2010年的时候 Spring 还是 SSH 三大框架之一,到了今天 Spring 要说自己是老二,还这没有人敢说自己是第一。
正是因为 Spring 在 Java 社区中有如此强大的影响力,所以在 Spring Boot 一出生的时候,就受到了广大社区爱好者的关注、使用、写教程、贡献代码、提 Bug。正是因为庞大的开源爱好者,才一起反铺 Spring Boot ,让 Spring Boot 发展这么快,这么好。
如果你想系统的学习 Spring Boot ,给大家推荐一个 Spring Boot 中文索引,收集了 Spring Boot 中文社区的所有学习资料,地址: springboot.fun/
3. 时代背景
3.1 微服务
- 微服务是一种架构风格
- 一个应用拆分为一组小型服务
- 每个服务运行在自己的进程内,也就是可独立部署和升级
- 服务之间使用轻量级 HTTP 交互
- 服务围绕业务功能拆分
- 可由全自动部署机制独立部署
- 服务自治,服务可以使用不同的语言、不同的存储技术
3.2 分布式
分布式的难点:
- 远程调用
- 寻找服务
- 负载均衡
- 服务容错
- 配置管理
- 服务监控
- 链路追踪
- 日志管理
- 任务调度
- ...
分布式的解决:
- Spring Boot + SpringCloud
3.3 云原生
原生应用如何上云:Cloud Native
上云的困难:
- 服务自愈
- 弹性伸缩
- 服务隔离
- 自动化部署
- 灰度发布
- 流量治理
- ...
上云的解决:
- 容器化
- 微服务
- DevOps
- 持续交付
4. Spring Boot 快速入门
You can use Spring Boot to create Java applications that can be started by using java -jar
or more traditional war deployments. We also provide a command line tool that runs “spring scripts”.
4.1 系统要求
Spring Boot 2.5.4 需要Java 8,并且兼容 Java 16(包括 Java 16) 。还需要Spring Framework 5.3.9或更高版本。
为以下构建工具提供了显式构建支持:
Build Tool | Version |
---|---|
Maven | 3.5+ |
Spring Boot 支持以下嵌入式 Servlet 容器:
Name | Servlet Version |
---|---|
Tomcat 9.0 | 4.0 |
4.2 开发第一个 Spring Boot 应用程序
pom.xml 引入依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
创建主程序:
/**
* @SpringBootApplication:这是一个 Spring Boot 应用!
*/
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
编写业务代码:
@RestController
public class Hello {
@RequestMapping("/hello")
public String hello_world() {
return "Hello Spring Boot!";
}
}
至此,一个简单的 Spring Boot 应用程序就完成~
4.3 简化部署
要创建一个可执行的 JAR,我们需要添加 spring-boot-maven-plugin
到我们 pom.xml
中。为此,请在该 dependencies
部分下方插入以下几行:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
5. Spring Boot 依赖管理
spring-boot-dependencies 中声明了开发中常用依赖的版本号,无需关注版本号(自动版本仲裁机制)
<properties>
<activemq.version>5.15.10</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.76</appengine-sdk.version>
<artemis.version>2.6.4</artemis.version>
<aspectj.version>1.9.4</aspectj.version>
...
</properties>
用户自定义版本:
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
6. Starter 场景启动器
spring-boot-starter-*
:只要引入 starter
,该场景的所有常规需要的依赖都会自动引入。
例如:
<dependencies>
<!--web开发的起步依赖: 提供 web 以及 MVC 和 validator 等web开发框架的支持。-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Test启动器:提供测试模块的支持,如:Junit -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Spring Boot 所有支持的场景:docs.spring.io/spring-boot…
所有场景最底层的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
7. Spring Boot 容器功能
7.1 组件添加
7.1.1 @Bean
@Bean
标记的方法的返回值会被当成组件导入 IOC 容器中,唯一需要注意的点就是 @Bean
返回的组件 id
为该注解标注的方法名!
public class MyConfig {
@Bean // 注入容器的组件 id 为该注解标记的方法名(此处 id="getPerson")
public Person getPerson() {
return new Person("w", new Date(), 21);
}
}
再举一个例子(该例值得斟酌):
// 返回 MultipartResolver 组件, id="multipartResolver"
@Bean
// 当容器中存在 MultipartResolver 类型(class)的组件
@ConditionalOnBean(MultipartResolver.class)
// 当容器中不存在 multipartResolver 名(id)的组件【结合上一句注释理解一下!】
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
// 给 @Bean 标注的方法传入了对象参数,这个参数的值就会从容器中找!
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// 有以上条件后,当 IOC 容器中存在 id 不规范(id!="multipartResolver")的 MultipartResolver 组件时,
// 就会将其转为 id="multipartResolver" 的 MultipartResolver 类型的组件
// 作用:Spring Boot 就能防止有些用户配置的文件上传解析器不符合规范
return resolver;
}
7.1.2 @Configuration
被 @Configuration
标注的类称为配置类,配置类本身也是组件。
@Configuration
public class MyConfig {
@Bean
public Person getPerson() {
return new Person("w", new Date(), 21);
}
}
7.1.3 @Import
@Configuration
@Import({Person.class, GsonJsonParser.class})
public class MyConfig {
@Bean
public Person getPerson() {
return new Person("w", new Date(), 21);
}
}
7.1.4 @ImportSelector
@Configuration
@Import({Person.class, MyImportSelector.class})
public class MyConfig {
@Bean
public Person getPerson() {
return new Person("w", new Date(), 21);
}
}
MyImportSelector.java:
public class MyImportSelector implements ImportSelector {
// 返回值:导入到容器的组件的全类名
// AnnotationMetadata:当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.one.bean.Person", "com.one.controller.SpringController"};
}
}
7.1.5 @Conditional
@Conditional
是 Spring4 新提供的注解,它的作用是按照一定的条件进行判断,满足条件则向容器注册组件。
@Configuration
@Import({MyImportSelector.class})
public class MyConfig {
@ConditionalOnBean(name = "color") // 当且仅当容器中含有 id = 'color' 的组件,才会执行以下的注入组件方法
@Bean // 注入容器的组件 id 为该注解标记的方法名(此处 id="getPerson")
public Person getPerson() {
return new Person("w", new Date(), 21);
}
}
7.2 原生配置文件的引入
7.2.1 @ImportResource
如果已经拥有了 xml 配置文件,但由于配置过多,你不想浪费时间将其全部转换为注解,那么 @ImportResource
就派上用场了。
@Configuration
@Import({MyImportSelector.class})
@ImportResource("classpath:bean.xml") // 导入xml配置文件: 省去转换为注解的工作
public class MyConfig {
@ConditionalOnBean(name = "color")
@Bean
public Person getPerson() {
return new Person("w", new Date(), 21);
}
}
7.3 配置绑定
以前我们都是编写 Properties 配置文件,然后通过 Java 读取到 Properties 文件中的内容,然后将其封装到 JavaBean 中,以供随时使用。
现在我们可以使用注解替代这一模式。
7.3.1 @Component
+ @ConfigurationProperties
@Component
注解必不可少:因为只有在容器中的组件,才能拥有 Spring Boot 提供的强大功能!
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String userName;
private Date date;
private int age;
// ignore Setter、Getter
}
如上图,在实现配置绑定(填写 application.yml)之前,我们会遇到 IDEA 给出的提示:没有在类路径下找到 configuration-processor
。其实它就是提供自定义类绑定的配置提示,我们顺着点击 Open Documentation
便可根据提供的文档信息完成依赖引入。
application.yml:
person:
date: 2021/07/26
age: 19
user-name: Kun
pom.xml:
<!-- 绑定提示! -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
编写 controller 测试属性是否成功注入:
@RestController
public class SpringController {
@Autowired
private Person person;
@RequestMapping("person1")
public Person person() {
return person;
}
}
7.3.2 @EnableConfigurationProperties
+ @ConfigurationProperties
@EnableConfigurationProperties
只能在配置类中标注(即含有 @Configuration
)才能生效。
@Configuration
@EnableConfigurationProperties(Person.class)
// 1.开启Person的配置绑定功能(@ConfigurationProperties)
// 2.将Person组件注册到容器中(尽管没有 @Component)
public class MyConfig {
}
自定义类:
// 此时无需 @Component 注解
@ConfigurationProperties(prefix = "person")
public class Person {
private String userName;
private Date date;
private int age;
// ignore Setter、Getter
}
application.yml:
person:
date: 2021/07/26
age: 19
user-name: Kun
为什么要这样操作呢?直接使用刚刚第一种方法不是简单明了吗?
其实 @EnableConfigurationProperties
就是为了解决第三方包下的类无法标注 @Component
的问题!
7.4 默认的包结构
主程序所在包下的类以及子包下的所有组件(@Bean
、@Component
、@Controller
、@Service
、@Repository
)都会被默认扫描进 IOC 容器,无需再配置 @ComponentScan
;若你不想使用 @SpringBootApplication
,但也实现自定义包扫描路径,那么你便可以使用 @EnableAutoConfiguration
+ @ComponentScan
来替代。
The following listing shows a typical layout:
com
+- one
+- myapplication
+- MyApplication.java
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java
自定义包扫描路径:
【第一种】
【第二种】
@SpringBootApplication(scanBasePackages = "com.one")
8. 最佳实践
8.1 Positive matches & Negative matches
Spring Boot 底层帮我们进行自动配置【关于自动配置原理,详见下一篇文章】,若你想探究哪些自动配置生效(满足 @Conditional
),哪些未生效,则可以在 application.properties 中添加如下一行代码:
debug=true
运行主程序,输出结果【节选】:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
- found 'session' scope (OnWebApplicationCondition)
DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration' (OnClassCondition)
- Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration' (OnClassCondition)
- DispatcherServlet Registration did not find servlet registration bean (DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition)
DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration matched:
- @ConditionalOnBean (names: dispatcherServlet; types: org.springframework.web.servlet.DispatcherServlet; SearchStrategy: all) found bean 'dispatcherServlet' (OnBeanCondition)
...
Negative matches:
-----------------
GsonAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'com.google.gson.Gson' (OnClassCondition)
GsonHttpMessageConvertersConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'com.google.gson.Gson' (OnClassCondition)
ServletWebServerFactoryConfiguration.EmbeddedJetty:
Did not match:
- @ConditionalOnClass did not find required classes 'org.eclipse.jetty.server.Server', 'org.eclipse.jetty.util.Loader', 'org.eclipse.jetty.webapp.WebAppContext' (OnClassCondition)
ServletWebServerFactoryConfiguration.EmbeddedUndertow:
Did not match:
- @ConditionalOnClass did not find required classes 'io.undertow.Undertow', 'org.xnio.SslClientAuthMode' (OnClassCondition)
...
Exclusions:
-----------
None
Unconditional classes:
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
8.2 Lombok
pom.xml 引入:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
主要有以下 5 个注解:
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
稍微清楚有这么一个插件存在即可,不必深究;因为笔者也是比较反对使用 Lombok。主要有以下几个原因:
1. JDK版本问题
当我想要将现有项目的 JDK 从 Java 8 升级到 Java 11 时,我发现 Lombok 不能正常工作了。于是我不得不将所有的 Lombok 注解从项目源代码中清除,并使用 IDE 自带的功能生成 getter/setter
,equals
,hashCode
,toString
以及构造器等方法,你也可以使用 Delombok 工具完成这一过程。但这终究会消耗你很多的时间。
2. 胁迫使用
当你的源代码中使用了 Lombok,恰好你的代码又被其他的人所使用,那么依赖你代码的人,也必须安装 Lombok 插件(不管他们喜不喜欢),同时还要花费时间去了解 Lombok 注解的使用情况,如果不那么做,代码将无法正常运行。使用过 Lombok 之后,我发现这是一种很流氓的行为。
3. 可读性差
Lombok 隐藏了 JavaBean 封装的细节,如果你使用 @AllArgsConstructor
注解,它将提供一个巨型构造器,让外界有机会在初始化对象时修改类中所有的属性。首先,这是极其不安全的,因为类中某些属性我们是不希望被修改的;另外,如果某个类中有几十个属性存在,就会有一个包含几十个参数的构造器被 Lombok 注入到类中,这是不理智的行为;其次,构造器参数的顺序完全由 Lombok 所控制,我们并不能操控,只有当你需要调试时才发现有一个奇怪的 “小强” 在等着你;最后,在运行代码之前,所有 JavaBean 中的方法你只能想象他们长什么样子,你并不能看见。
4. 代码耦合度增加
当你使用 Lombok 来编写某一个模块的代码后,其余依赖此模块的其他代码都需要引入 Lombok 依赖,同时还需要在 IDE 中安装 Lombok 的插件。虽然 Lombok 的依赖包并不大,但就因为其中一个地方使用了 Lombok,其余所有的依赖方都要强制加入 Lombok 的 Jar 包,这是一种侵入式的耦合,如果再遇上 JDK 版本问题,这将是一场灾难。
5. 代码污染
使用 Lombok,一时觉得很爽,但它却污染了你的代码,破坏了 Java 代码的完整性,可读性和安全性,同时还增加的团队的技术债务,这是一种弊大于利,得不偿失的操作。如果你确实想让自己的代码更加精炼,同时又兼顾可读性和编码效率,不妨使用主流的 Scala 或 Kotlin 这一基于 JVM 的语言。
总之:使用 Lombok,会增加团队的技术债务,降低代码的可读性,增大代码的耦合度和调式难度。如果你正在参与一个团队项目(或大型项目),考虑到后续的升级与扩展,是否使用 Lombok,请与你的团队多沟通和三思。
8.3 DevTools
Spring Boot 为开发者提供了一个名为 spring-boot-devtools
的模块来使 Spring Boot 应用支持热部署,提高开发者的开发效率,无需手动重启 Spring Boot 应用。
Spring Boot 的 DevTools 为我们提供了一些便利的开发期工具,包括以下这些内容:
- 当代码变更后应用会自动重启
- LiveReload 服务器配合 LiveReload 浏览器插件,能够在模板 、图片 、样式表 、JavaScript 等发生变化时,自动刷新浏览器,这样就可以免去手动刷新的动作;
- 自动禁用模板框架(比如 Thymeleaf 或 FreeMarker)缓存;
⭐引用 devtools 依赖:
<!-- 服务器热部署: devtools 模块 -->
<!-- 浏览器热部署: LiveReload 插件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
8.3.1 自定义配置热部署
以下配置用于自定义配置热部署,可以不设置。
# 热部署开关,false 即不启用热部署
spring.devtools.restart.enabled=true
# 指定热部署的目录
spring.devtools.restart.additional-paths=src/main/java
# 指定目录不更新
spring.devtools.restart.exclude=test/**
8.3.2 devtools 原理
在发现代码有更改之后,重新启动应用,但是比速度比手动停止后再启动还要更快,更快指的不是节省出来的手工操作的时间。
其深层原理是使用了两个 ClassLoader,一个 Classloader 加载那些不会改变的类(第三方Jar包),另一个 ClassLoader 加载会更改的类,称为 Restart ClassLoader。一旦代码更改,原来的 Restart ClassLoader 被丢弃,重新创建一个 Restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间(5秒以内)。
8.3.3 为什么在 IntelliJ IDEA 中 spring-boot-devtools
热部署不生效?
因为在 IDEA 中自动编译是默认停止的,启动方法如下流程:
1、首先在设置中找到 Build project automatically 并勾选,即开启自动编译
2、接着使用组合键 Ctrl+Shift+Alt+/
调出 Maintenance(维护)控制台,选择 Registry
3、最后勾选 compiler.automake.allow.when.app.running(运行时自动编译)
注意事项:
- 生产环境 devtools 将被禁用,如
java -jar
方式或者自定义的类加载器等都会识别为生产环境 - 打包应用默认不会包含 devtools,除非你禁用 SpringBoot Maven 插件的
excludeDevtools
属性
8.4 Spring Initializr
也就是所谓的项目初始化向导,无需自己创建 Maven 工程后再编写 Spring Boot 项目的基本架构。
关键在这里,Spring Initializr 提供图形化的依赖勾选,无需自己在 pom.xml 中引入 starter。
大功告成:
以上便是 Spring Boot 基础入门知识的所有内容啦!