【已完成】本文大部分内容翻译自官方文档https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/using-spring-boot.html
在学习Spring Boot之前先提出几个问题:
在此,我找了几篇文章(鄙人没有经历过互联网项目架构的演变,只能从别人的文章中学习):
为什么会出现Spring Boot:http://www.sohu.com/a/212136259_100090656
为什么越来越多的开发者选择使用Spring Boot?:https://blog.csdn.net/xlgen157387/article/details/52830071
了解了上述几个问题之后,下一步了解怎么去使用。
Spring Boot官方文档
官方文档中提供了几种构建方式,这里使用Maven构建。
继承一个父工程,POM配置:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
parent>
在公司中你的项目可能已经配置了一个父工程,而那个父工程没有依赖Spring Boot,那么可以使用这种方式:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
如果你看spring-boot-starter-parent
的POM文件,会发现它继承spring-boot-dependencies
。
Spring Boot包含一个Maven插件,它可以将项目打包为一个可执行jar。如果要使用插件,请将其添加到
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
Starters是一个方便包含在应用程序中的依赖描述符。
你可以一次性获得所需的所有Spring和相关技术。例如你要构建一个Web应用程序,在你的工程POM文件中加入spring-boot-starter-web
依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
它包含许多依赖项,把所有你需要依赖的包都包含了,看看spring-boot-starter-web
的POM文件里面就可以找到它依赖了spring-web
和spring-webmvc
等。
所有官方的starters都类似spring-boot-starter-*
这种方式命名。官方文档中列出了常用的。
本地代码结构如下:
cn
+- shrmus
+- springboot
+- demo20191222
+- Application20191222.java
|
+- product
| +- Product.java
| +- ProductController.java
| +- ProductService.java
| +- ProductRepository.java
|
+- user
+- User.java
+- UserController.java
+- UserService.java
+- UserRepository.java
在Application20191222.java
文件中声明main
方法,加上@SpringBootApplication
注解,如下:
package cn.shrmus.springboot.demo20191222;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application20191222 {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Spring支持基于java的配置,虽然SpringApplication
可以和XML一起使用,但是建议主源类是一个@Configuration
类,在主源类中加载其他的配置。通常,定义main
方法的类可以作为主源类。
实际上面的Application20191222
类就是一个@Configuration
类,因为@SpringBootApplication
注解基于@Configuration
注解。
不建议把所有配置都放在一个类中,就像XML配置不建议把配置信息都存在一个文件中,可以用@Import
注解导入其他配置类,或者可以使用@ComponentScan
来自动获取所有Spring组件,包括标记了@Configuration
的类,也可以说是@Component
类。
用法如下:
@Import(
value = {
cn.shrmus.springboot.demo20191222.config.MysqlDataSource.class,
cn.shrmus.springboot.demo20191222.config.OracleDataSource.class
}
)
前提是value
中的类都是标记了@Configuration
的类。
用法如下:
@ComponentScan(
value = {
"cn.shrmus.springboot.demo20191222.config",
"cn.shrmus.springboot.demo20191222.user",
"cn.shrmus.springboot.demo20191222.product"
}
)
或者
@ComponentScan(
basePackages = {
"cn.shrmus.springboot.demo20191222.config",
"cn.shrmus.springboot.demo20191222.user",
"cn.shrmus.springboot.demo20191222.product"
}
)
上面的value
和basePackages
等价。@ComponentScan
还有其他的用法,就需要读者自己去摸索了。
可以声明多个@ComponentScan
,用法如下:
@ComponentScans(
value = {
@ComponentScan(value = {"cn.shrmus.springboot.demo20191222.config"}),
@ComponentScan(value = {"cn.shrmus.springboot.demo20191222.user"}),
@ComponentScan(value = {"cn.shrmus.springboot.demo20191222.product"})
}
)
另外还有@ConfigurationPropertiesScan
,@EnableConfigurationProperties
,@ConfigurationPropertiesBinding
,@EntityScan
,@ImportAutoConfiguration
读者可以自己尝试怎么使用。
如果必须使用基于XML的配置,建议从标记了@Configuration
的类开始,再使用@ImportResource
注解加载XML配置文件,用法如下:
@ImportResource(
value = {
"classpath:config/spring/applicationContext-MysqlDataSource.xml",
"classpath:config/spring/applicationContext-OracleDataSource.xml"
}
)
如果必须使用properties文件,而这个文件又是自定义的,可以用@PropertySource
注解,用法如下:
@PropertySource(value = "config/dataSource/mysqlDataSource.properties")
如果配置信息在application.properties
中,则可以省略此注解。
Spring Boot自动配置是基于你添加的jar依赖尝试去做自动配置。
你可以选择@EnableAutoConfiguration
或@SpringBootApplication
注解加入到@Configuration
类中。
你可以定义自己的配置来替换自动配置的特定部分。
在classpath
中下新建一个META-INF目录,在这个目录下新建一个spring.factories
文件。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.shrmus.springboot.demo20191222.autoconfigure.MysqlDataSourceAutoConfiguration
如果你需要了解当前应用的是什么自动配置,以及为什么,请使用--debug
开关启动您的应用程序。这样做可以为选择的核心日志记录器启用调试日志,并将条件报告记录到控制台。
启动--debug
的配置方式:
--debug
如果你发现你不想要的特定的自动配置类被应用,你可以使用@EnableAutoConfiguration
的exclude
属性来禁用它们,如下面的例子所示:
package cn.shrmus.springboot.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration(exclude = {cn.shrmus.springboot.demo20191222.autoconfigure.MysqlDataSourceAutoConfiguration.class})
public class MysqlDataSource {
}
如果要禁用的类不在classpath
中,也可以使用excludeName
属性指定类的全限定名,用法如下:
@SpringBootApplication(excludeName = "cn.shrmus.springboot.demo20191222.autoconfigure.MysqlDataSourceAutoConfiguration")
还可以使用spring.autoconfigure.exclude
来控制要排除的自动配置类列表。在application.properes
文件中,用法如下:
spring.autoconfigure.exclude=cn.shrmus.springboot.demo20191222.autoconfigure.MysqlDataSourceAutoConfiguration
所有应用程序组件(@Component
、@Service
、@Repository
、@Controller
等)都自动注册为Spring bean。
下面用构造方法注入来获得一个UserRepository Bean:
package cn.shrmus.springboot.demo20191222.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService implements IUserService{
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
如果bean只有一个构造方法,可以省略@Autowired
。
使用@SpringBootApplication
注解可以启用这三个特性:
@EnableAutoConfiguration
:启用Spring Boot的自动配置机制。@ComponentScan
:开启扫描,在应用程序的包中扫描@Component
类。@Configuration
:允许在上下文中注册额外的bean或导入额外的配置类。如果你不想在应用程序中使用@Component
扫描或@ConfigurationProperties
扫描:
package cn.shrmus.springboot.demo20191222;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
public class Application20191222 {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这时候会发现,user包和product包中的@Component
类都没有注入到容器中。
本节只讨论基于jar的打包。如果选择将应用程序打包为war文件,应该参考服务器和IDE文档。
打包方案一:
MANIFEST.SF
文件的路径 MANIFEST.SF
文件,而文件中的内容就是启动类的配置信息呵呵版本信息 打包方案二:
如果是继承spring-boot-starter-parent
,只需在POM中添加
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
打包方案三:
如果不是继承spring-boot-starter-parent
而是使用依赖管理spring-boot-dependencies
,则添加:
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<mainClass>cn.shrmus.springboot.demo20191222.Application20191222mainClass>
configuration>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
创建jar后,你可以使用java -jar
来运行您的应用程序,如下面的例子所示:
java -jar target/demo20191222-springboot-1.0-SNAPSHOT.jar
还可以在启用远程调试支持的情况下运行打包的应用程序。这样做可以将调试器附加到打包的应用程序中,如下面的示例所示:
java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar target/demo20191222-springboot-1.0-SNAPSHOT.jar
mvn spring-boot:run
IDEA开发工具中用Maven命令运行应用程序的方式:
方式一:
spring-boot:run
方式二:
方式三:
spring-boot:run
export MAVEN_OPTS=-Xmx1024m
在程序运行过程中交换字节码,可使用JRebel。
使用spring-boot-devtools
模块支持快速重启应用程序。
添加spring-boot-devtools
模块可以使应用程序开发体验更愉快。
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
dependencies>
在运行完全打包的应用程序时,将自动禁用开发人员工具。如果您的应用程序是从java -jar
启动的,或者是从一个特殊的类加载器启动的,那么它就被认为是一个“生产应用程序”,如果您在容器中运行应用程序,可以排除devtools或设置spring.devtools.restart.enabled=false
。
默认情况下,重新打包的归档文件不包含devtools。如果您想使用某个远程devtools特性,您需要禁用excludeDevtools
构建属性来包含它。该属性同时受到Maven和Gradle插件的支持。
Spring Boot支持的几个库使用缓存来提高性能。例如,模板引擎缓存已编译的模板,以避免重复解析模板文件。此外,在提供静态资源时,Spring MVC可以向响应添加HTTP缓存标头。
虽然缓存在生产环境中非常有用,但在开发过程中可能会适得其反,使您无法看到刚才在应用程序中所做的更改。出于这个原因,spring-boot-devtools默认禁用缓存选项。
缓存选项通常由application.properties
文件设置。例如,Thymeleaf提供了spring.thymeleaf.cache
属性,不需要手动设置这些属性,spring-boot-devtools
模块自动应用合理的开发时配置。
由于在开发Spring MVC和Spring WebFlux应用程序时需要更多关于web请求的信息,所以开发人员工具将为web日志组启用DEBUG
日志。这将为您提供有关传入请求、正在处理它的处理程序、响应结果等信息。如果希望记录所有请求细节(包括潜在的敏感信息),可以打开spring.http.log-request-details
配置属性。
如果不希望应用属性默认值,可以将application.properties
中的spring.devtools.add-properties
设置为false
。
使用spring-boot-devtools
的应用程序会使在classpath中的文件发生更改时自动重新启动。默认情况下,classpath中指向文件夹的任何条目都将被监视,以查看是否有更改。某些资源(如静态资产和视图模板)不需要重新启动应用程序。
触发重启
由于DevTools监视类路径资源,触发重新启动的惟一方法是更新类路径。更新类路径的方式取决于所使用的IDE。
在Eclipse中,保存修改后的文件将导致更新类路径并触发重启。
在IntelliJ IDEA中,构建项目(菜单[Build]–>[Build Project])具有相同的效果。
与LiveReload一起使用时,自动重启效果非常好。如果使用JRebel,则禁用自动重新启动,以便动态类重新加载。其他devtools特性(如LiveReload和属性覆盖)仍然可以使用。
DevTools在重启时依赖于应用程序上下文的shutdown hook去关闭。如果禁用了shutdown hook(SpringApplication.setRegisterShutdownHook(false)
)它将无法正常工作。
当classpath上的一个条目更改时,决定是否应该触发重启时,DevTools会自动忽略名为spring-boot
、spring-boot- DevTools
、spring-boot-autoconfigure
、spring-boot-actuator
和spring-boot-starter
的项目。
DevTools需要使用ApplicationContext
自定义ResourceLoader
。如果您的应用程序已经提供了一个,那么它将被包装。ApplicationContext
不支持直接覆盖getResource
方法。
重新启动和重新加载
重启技术来自于Spring Boot提供的两个类加载器。
基类加载器(base classloader):不更改的类(例如,来自第三方jar的类)将加载到base类加载器中。
重启类加载器(restart classloader):你正在开发的类被加载到restart加载器中。
当应用程序重新启动时,restart类加载器被丢弃并且创建一个新的restart类加载器。这种方法意味着应用程序重新启动通常比“冷启动”快得多,因为基类加载器已经可用并被填充了。
如果你发现重新启动对于您的应用程序来说不够快,或者你遇到了类加载问题,那么你可以考虑重新加载技术,例如来自ZeroTurnaround的JRebel。这些工作是通过在装入类时重写它们,使它们更易于重新装入。
默认情况下,每次应用程序重新启动时,都会记录一个显示条件评估增量的报告。该报告显示了在进行更改(如添加或删除bean和设置配置属性)时对应用程序自动配置的更改。
若要禁用报告的日志记录,请设置以下属性:
spring.devtools.restart.log-condition-evaluation-delta=false
某些资源在更改时不一定需要重新启动。例如Thymeleaf模板可以直接编辑。
默认情况下,在/META-INF/maven
、/META-INF/resources
、/resources
、/static
、/public
或/templates
中更改资源不会触发重新启动,但会触发动态重新加载。
如果您想要自定义这些排除,您可以使用spring.devtools.restart.exclude
属性。
例如,要排除/static
和/public
,您需要设置以下属性:
spring.devtools.restart.exclude=static/**,public/**
如果您想要保留这些默认值并添加额外的排除,那么可以使用spring.devtools.restart.additional-exclude
属性。
当你更改不在classpath中的文件时,你希望重新启动或重新加载应用程序。
使用spring.devtools.restart.additional-paths
属性来配置额外的路径以观察变化。
可以使用spring.devtools.restart.exclude
属性来控制其他路径下的更改是触发完全重新启动还是实时重新加载。
如果不想使用重启特性,可以使用spring.devtools.restart.enabled
属性禁用。
在大多数情况下,可以在application.properties
中设置这个属性。
这样做仍然会初始化restart类加载器,但它不会监视文件更改。
如果你需要完全禁用重启,就要在调用SpringApplication.run(…)
之前将spring.devtools.restart.enabled
系统属性设置为false
。如下所示:
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}
如果你使用的IDE不断编译修改的文件,而你可能更希望只在特定的时间触发重新启动。
你可以使用“触发器文件”,它是一个特殊的文件,当您想要触发重启检查时,必须修改它(对文件的任何更新都将触发一次检查,但是只有在Devtools检测到需要执行某些操作时,才会实际重新启动)。
要使用触发器文件,请将spring.devtools.restart.trigger-file
属性设置为触发器文件的名称(不包括任何路径),触发器文件必须在classpath下。
例如,如果你有一个具有以下结构的项目:
src
+- main
+- resources
+- .reloadtrigger
那么trigger-file
属性设置成:
spring.devtools.restart.trigger-file=.reloadtrigger
现在只有src/main/resources/.reloadtrigger
被修改才会触发重启。
如果想要把spring.devtools.restart.trigger-file
设置为全局设置,以便所有项目都以相同的方式运行。
有些IDE可以使你不用手动更新触发器文件,使用Spring工具,您可以从控制台视图中使用“reload”按钮(只要您的触发文件名为.reloadtrigger)。
正如重新启动和重新加载一节中所描述的,重新启动功能是通过使用两个类加载器实现的。
对于大多数应用程序,这种方法工作得很好。然而,它有时会导致类加载问题。
默认情况下,IDE中任何打开的项目都是用“restart”类加载器加载的,而任何正规的.jar
文件都是用“base”类加载器加载的。
如果您处理的是一个多模块项目,然而并不是每个模块都要导入到IDE中,那么您可能需要自定义一些东西。你可以创建一个META-INF/spring-devtools.properties
文件。
The
spring-devtools.properties
file can contain properties prefixed withrestart.exclude
andrestart.include
. Theinclude
elements are items that should be pulled up into the “restart” classloader, and theexclude
elements are items that should be pushed down into the “base” classloader.
这个spring-devtools.properties
文件可以包含restart.exclude
和restart.include
前缀。
include
是一个数组,数组中的元素被“restart”类加载器加载。
exclude
也是一个数组,数组中的元素被“base”类加载器加载。
(原文中的pulled up和pushed down一直没能理解是什么意思,经过讨论后,只有关注include
和exclude
中的元素被谁来执行,而没有去特意解释这两个短语的意思)
数组元素的值是一个被应用到classpath中的正则表达式,如下所示:
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\.]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\.]+\.jar
所有属性的key必须是唯一的,只要以restart.include
或restart.exclude
开头,它就被考虑在内。
classpath下所有的META-INF/spring-devtools.properties
都会被加载,你可以将文件打包到项目内部或项目使用的库中。
使用标准ObjectInputStream反序列化的对象,重新启动功能不能很好地工作。
如果需要反序列化数据,可能需要结合使用Spring的ConfigurableObjectInputStream
和Thread.currentThread().getcontextclassloader()
。
不幸的是,一些第三方库在反序列化时没有考虑上下文类加载器。如果您发现这样的问题,您需要向原始作者请求修复。
模块spring-boot-devtools
包含一个内嵌的LiveReload服务器,可以用来在资源更改时触发浏览器刷新。
从livereload.com可以免费获得Chrome、Firefox和Safari的LiveReload浏览器扩展。
如果您不想在应用程序运行时启动LiveReload服务器,将spring.devtools.livereload.enabled
属性设置为false
。
一次只能运行一个LiveReload服务器。在启动应用程序之前,确保没有其他的LiveReload服务器在运行。如果您从IDE启动多个应用程序,那么只有第一个具有LiveReload支持。
你可以通过向$HOME/.config/spring-boot
文件夹下添加以下任何文件来配置全局devtools设置:
spring-boot-devtools.properties
spring-boot-devtools.yaml
spring-boot-devtools.yml
任何被添加到这些文件中的属性都适用于所有使用devtools的Spring启动应用程序。
例如,配置一直使用触发器文件去重启,你需要添加下列属性:
~/.config/spring-boot/spring-boot-devtools.properties
spring.devtools.restart.trigger-file=.reloadtrigger
如果$HOME/.config/spring-boot
中没有找到devtools配置文件,在$HOME
文件夹的根目录搜索是否存在.spring-boot-devtools.properties
文件。
这允许你与不支持$HOME/.config/spring-boot
位置的旧版Spring Boot应用程序共享devtools全局配置。
在上述文件中激活的配置文件不会影响加载特定的配置文件
远程代码更新的意思是,在本地IDE修改代码,可以自动更新到服务器上,并且自动重启生效。就像在本地开发环境一样。(来自Spring Boot Remote Application)
Spring Boot developer tools并不局限于本地开发。在运行远程应用程序时,你还可以使用一些特性。
远程支持是可选的,因为启用它可能存在安全风险。仅当在受信任的网络上运行或使用SSL进行保护时,才应该启用它。如果这两个选项都不可用,就不应该在生产环境上使用DevTools的远程支持。
要启用它,您需要确保重新打包的归档文件中包含devtools
,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludeDevtools>falseexcludeDevtools>
configuration>
plugin>
plugins>
build>
然后设置spring.devtools.remote.secret
属性,与任何重要的密码或秘密一样,该值应该是惟一的、强的,这样就不会被猜测或强行使用。
远程devtools支持由两部分支持:
等待连接的服务端结点和在你的IDE中运行的客户端应用程序。
当设置spring.devtools.remote.secret
属性时,服务器组件将自动启用。客户端组件必须手动启动。
远程客户端应用程序需要与你连接的远程应用程序具有相同的classpath。在classpath中运行org.springframework.boot.devtools.RemoteSpringApplication
。应用程序唯一需要的参数是它所连接的远程URL。
如果你使用Eclipse或者STS,你有一个名为my-app
的项目已经部署到Cloud Foundry云平台上,你还需要做下列事情:
my-app
项目 org.springframework.boot.devtools.RemoteSpringApplication
作为main class https://myapp.cfapps.io
(你的远程URL)到Program arguments
Because the remote client is using the same classpath as the real application it can directly read application properties.
因为远程客户端应用程序与云平台的应用程序使用相同的classpath,所以云平台的应用程序可以直接读取远程客户端应用程序的属性。(官方文档中的real project和it让我有点迷糊,网上的大多是机器翻译,正所谓理论来自于实践,我就去试了一下,得到了这段翻译)
这就是spring.devtools.remote.secret
属性被读取并传到服务器端进行身份验证的方法。
通常建议使用https://
作为连接协议,因为通信是加密的,密码不能被截获。
如果需要使用代理访问远程应用程序,配置spring.devtools.remote.proxy.host
和spring.devtools.remote.proxy.port
属性。
远程客户端监视应用程序classpath中的更改,与监视本地重启的方式相同。
任何更新的资源都被推送到远程应用程序,并(如果需要)触发远程应用程序重新启动。
如果你在本地没有云服务的特性上进行迭代,这可能会很有帮助。通常,远程更新和重新启动比完整的重新构建和部署周期要快得多。
只有在远程客户端运行时才监控文件。如果在启动远程客户端之前更改文件,则不会将其推到远程服务器。
FileSystemWatcher的工作方式是,在一定的时间间隔内轮询类更改,然后等待预定义的静默期,以确保不再发生更改。
然后将更改上传到远程应用程序。在较慢的开发环境中,可能会发生这样的情况:安静期不够长,类中的更改可能被分成批。
上传第一批类更改后,服务器将重新启动。下一批数据不能发送到应用程序,因为服务器正在重新启动。
这通常表现在RemoteSpringApplication
日志中关于上传一些类失败的警告,以及随后的重试。但它也可能导致应用程序代码不一致,并且在上传第一批更改后无法重新启动。
如果你经常观察这些问题,尝试将spring.devtools.restart.poll-interval
和spring.devtools.restart.quiet-period
参数的值增加到适合您的开发环境中:
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
被监视的classpath文件夹现在每2秒轮询一次,以查找更改,并保持1秒的静默期,以确保没有其他类更改。
可执行jar可用于生产部署。由于它们是自包含的,所以也非常适合基于云的部署。
对于其他“生产就绪”特性,如health、auditing和metric REST或JMX结点,可以考虑添加spring-boot-actuator
。有关详细信息,请参阅production-ready-features.html。