文章作者:Tyan
博客:noahsnail.com | CSDN | 简书
19. 运行你自己的应用
将应用打包成jar并使用内嵌HTTP服务器的一个最大优势是你可以在任何地方运行你的程序。调试Spring Boot应用也很容易;你不必指定任何特定的IDE插件或扩展。
这一节只包含基于jar的打包,如果你想选择将你的应用打包成war文件,你应该参考你的服务器和IDE文档。
19.1 从IDE运行
你可以在你的IDE中运行一个Spring Boot应用将像运行一个简单的Java应用一样,然而,首先你需要导入你的工程。导入步骤根据你的IDE和构建系统会有所变化。大多数IDE可以直接导入Maven工程,例如Eclipse用户可以选择从File
菜单选择Import…
→ Existing Maven Projects
。
如果你不能直接将工程导入你的IDE中,你可以使用构建插件生成一个IDE元数据。Maven中包含Eclipse和IDEA的插件;Gradle有各种IDEs的插件。
如果你偶然的运行一个web应用两次,你会看到一个
Port already in use
错误。为了确保任何现有的实例被关闭,STS用户可以使用Relaunch
按钮而不是Run
按钮。
19.2 运行一个打包的应用
如果你使用Spring Boot的Maven或Gradle插件来创建一个可执行的jar包,你可以通过使用java -jar
来运行你的应用。例如:
$ java -jar target/myproject-0.0.1-SNAPSHOT.jar
它也支持以远程调试模式运行一个打包的应用。这允许你在打包的应用中添加一个调试器:
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar target/myproject-0.0.1-SNAPSHOT.jar
19.3 使用Maven插件
Spring Boot Maven插件包含一个run
目标,可以用来快速编译并运行你的应用。应用以exploded形式运行,就像在IDE中运行一样。
$ mvn spring-boot:run
你也可以使用有用的操作系统环境变量:
$ export MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=128M
19.4 使用Gradle插件
Spring Boot Gradle插件也包含一个bootRun
任务,它可以以exploded方式运行你的应用。当你导入spring-boot-gradle-plugin
时,可以添加bootRun
任务:
$ gradle bootRun
你也可以使用有用的操作系统环境变量:
$ export JAVA_OPTS=-Xmx1024m -XX:MaxPermSize=128M
19.5 热交换
由于Spring Boot应用只是普通的Java应用,JVM热交换应该是开箱即用的。JVM热交换可以替换的字节码有限制,一个更全面的解决方案是JRebel或Spring Loaded工程。spring-boot-devtools
模块也支持快速的应用重启。
更多细节请看20章,下面的开发者工具部分和怎样热交换部分。
20. 开发者工具
Spring Boot包含额外的工具集合,可以使应用开发的过程更方便一点。spring-boot-devtools
模块可以包含进任何工程,用来提供额外的程序调试特性。为了添加工具支持,简单的添加模块依赖到你的构建系统中:
Maven.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Gradle.
dependencies {
compile("org.springframework.boot:spring-boot-devtools")
}
当运行一个完整的打包应用时,开发者工具会自动失效。如果你的应用是通过
java -jar
启动的,或者是通过一个特定的类加载器启动的,那它会被当做一个『产品级应用』。将依赖标记为optional
是阻止开发工具间接应用到使用你应用的其它模块的最佳实践。Gradle不支持optional
依赖开箱即用,同时你可能想看看propdeps-plugin。
再打包文件默认不包含开发者工具。如果你想使用某些远程开发者工具特性,你需要让
excludeDevtools
构建属性包含它。Maven和Gradle插件都支持这个属性。
20.2 自动重启
当classpath
中的文件修改时,使用spring-boot-devtools
的应用会自动重启。当使用IDE开发时,这是一个很有用的功能,因为代码改变时它能快速的进行反馈。默认情况下,会监控classpath
指向的文件夹中任何条目的变化。注意某些资源例如静态资源和视图模板不需要重启应用。
触发重启
作为
DevTools
监视器classpath
中的资源,触发重启的唯一方式是更新classpath
。引起classpath
更新的方式取决于你使用的IDE。在Eclipse中,保存一个修改的文件将引起classpath
更新并触发重启事件。在IntelliJ IDEA中,构建工程(Build → Make Project
)将会有同样的效果。
只要启用了分支,你也可以通过支持的构建系统启动你的应用(例如,Maven和Gradle),因为
DevTools
需要一个独立的应用类加载器来进行正确操作。当Gradle和Maven在classpath
中检测到DevTools
时,它们默认的进行了那个工作。
当使用
LiveReload
,自动重启能很好的工作。更多细节请看下面。如果你使用JRebel
进行自动重启,将不支持动态的类重加载。其它的开发者工具功能(例如LiveReload
和属性覆写)仍能继续使用。
DevTools
依赖应用上下文关闭钩子来进行重启期间的关闭。如果你禁用了关闭钩子它将不能正确工作(SpringApplication.setRegisterShutdownHook(false)
)。
当决定
classpath
中输入引起的改变是否应该触发重启时,DevTools
会自动忽略命名为spring-boot
,spring-boot-devtools
,spring-boot-autoconfigure
,spring-boot-actuator
和spring-boot-starter
的工程。
重启与重载(重新加载)
Spring Boot提供的重启技术是通过两个类加载器进行工作的。加载进基类加载器的类不能改变(例如,那些第三方jar包)。那些你正在开发的类加载进重启类加载器中。当应用重启时,丢弃旧的重启类加载器并创建一个新的。这种方法意味着应用重启时比『冷启动』更快,因为基类加载器已经存在并可用。
如果你发现你的应用重启不够快,或者你碰到了类加载问题,你可以考虑重载技术例如ZeroTurnaround的JRebel。这些工作通过加载时类的重写使它们更适合重载。Spring加载提供了另一种选择,但许多框架都不支持,也不支持商业化。
20.2.1 例外资源
某些资源当它们改变时不一定需要触发重启。例如,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
属性。
20.2.2 监控其它路径
当你修改不在classpath
中的文件时,你可能也想重启或重载你的应用。为了这样做,可以使用spring.devtools.restart.additional-paths
属性来监控其它路径上的变化。你可以使用前面描述的spring.devtools.restart.exclude
属性来控制其它路径上的变化是否会触发重启或仅触发实时重载。
20.2.3 禁用重启
如果你想使用重启功能你可以通过spring.devtools.restart.enabled
属性禁用它。大多数情况下你可以在你的application.properties
中设置它(这仍会初始化重启类加载器但它不会监控文件的变化)。
如果你需要完整的禁用重启支持,例如,因为它不能与一个特定的库一起工作,你需要在调用SpringApplication.run(…)
之前设置一个System
属性。例如:
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}
20.2.4 使用触发器文件
如果你的IDE可以持续编译变化的文件,你可以只在特定的时间触发重启。为了实现这个功能你可以使用『触发器文件』,当你需要真正触发重启检查时,它是一个你必须要修改文件。修改这个文件只触发重启检查,只有Devtools
检测到它必须要做些事情时,重启才会发生。触发器文件应该进行手动更新,或通过IDE插件更新。
为了使用触发器文件需要使用spring.devtools.restart.trigger-file
属性。
为了使你所有的工程都表现一样,你需要将
spring.devtools.restart.trigger-file
设置为全局设置。
20.2.5 定制重启类加载器
像前面的的Restart vs Reload
部分所讲的那样,重启功能是通过两个类加载器实现的。对于大多数应用来说这个方法能很好的工作,但是有时候它也会引起一些类加载问题。
默认情况下,IDE中的任何开放的工程都会使用“restart”类加载器进行加载,任何规范的.jar
文件都会使用“base”类加载器进行加载。如果你在一个多模块工程中工作,不是每一个模块都导入到你的IDE中,你可能需要定制一些东西。为了实现这个功能你可以创建一个META-INF/spring-devtools.properties
文件。
spring-devtools.properties
可以包含restart.exclude.
和restart.include.
前缀属性。include
元素应该拉进“restart”类加载器中,exclude
元素应该推入到“base”类加载器中。属性值是应用到classpath
中的一个正则表达式。
例如:
restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar
所有属性的键必须是唯一的。只要
restart.include.
或restart.exclude
作为一个属性启动,它就被应用。
classpath
中的所有META-INF/spring-devtools.properties
都会被加载。你可以将文件打包进你的工程中,或这个工程使用的库中。
20.2.6 已知的限制
当存在使用标准ObjectInputStream
进行反序列化的对象时,重启功能不能很好的工作。如果你需要反序列化数据,你可能需要使用Spring的ConfigurableObjectInputStream
和Thread.currentThread().getContextClassLoader()
。
遗憾的是,一些第三方库反序列化时没有考虑上下文类加载器。如果你发现了这样的问题,你需要请求原作者进行修正。
20.3 实时重载
spring-boot-devtools
模块包含一个内嵌的实时重载服务器,当资源改变时可以用来触发浏览器重新刷新。实时重载浏览器扩展对于livereload.com中的Chrome,Firefox和Safari而言是可用的。
当你的应用运行时,如果你不想启动实时重载服务器,你可以将spring.devtools.livereload.enabled
属性设为false
。
一次你只可以运行一个实时重载服务器。在启动你的应用之前,确保没有其它的实时重载服务器在运行。如果你从你的IDE中启动多个应用,只有第一个应用有实时重载服务器支持。
20.4 全局设置
通过添加一个名为.spring-boot-devtools.properties
的文件到你的$HOME
文件夹中(注意文件名以.
开头),你可以配置全局开发者工具设置。任何添加到这个文件的属性都将应用到你机器上所有使用开发者工具的Spring Boot应用中。例如,为了配置重启时总是使用一个触发器文件,你需要添加如下内容:
~/.spring-boot-devtools.properties.
spring.devtools.reload.trigger-file=.reloadtrigger
20.5 远程应用
Spring Boot开发者工具是不受本地环境限制的,在运行远程应用时你也可以使用一些功能。远程支持是选择性加入的,为了使它起作用你需要确保devtools
包含在再打包的文件中:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
然后你需要设置spring.devtools.remote.secret
属性,例如:
spring.devtools.remote.secret=mysecret
使
spring-boot-devtools
在远程应用上起作用是有安全风险的。在产品部署时,你不应该让它支持spring-boot-devtools
。
远程devtools
需要两部分提供支持:一个接收连接的服务器端,一个运行在IDE中的客户端应用。当设置spring.devtools.remote.secret
属性时,服务器组件会自动起作用。客户端组件必须手动启动。
20.5.1 运行远程客户端应用
远程客户端应用设计要在你的IDE中运行。你需要运行org.springframework.boot.devtools.RemoteSpringApplication
,与要连接的远程工程要使用同样的classpath。传给应用的非可选参数应该是你要连接的远程URL。
例如,如果你在使用Eclipse或STS,你有一个名为my-app
的工程,它已经部署到了云计算中,你需要按照下面的步骤去做:
从
Run
菜单中选择Run Configurations…
。创建一个新的
Java Application
“launch configuration”。浏览
my-app
工程。使用
org.springframework.boot.devtools.RemoteSpringApplication
作为主类。添加
https://myapp.cfapps.io
到Program arguments
(或无论你的远程URL是什么)。
因为远程客户端与真实的应用使用的
classpath
相同,因此它可以直接读取应用属性。这就是spring.devtools.remote.secret
属性是怎样读取并传递给服务器进行授权的。
为了传输可以加密,密码不能被解析,建议总是使用
https://
作为连接协议。
如果你需要使用代理访问远程应用,配置
spring.devtools.remote.proxy.host
和spring.devtools.remote.proxy.port
属性。
20.5.2 远程更新
远程客户端会像本地重启那样监控你应用的classpath
的变化。任何资源的更新都会推送到远程应用并(如果需要的话)触发重启。如果你在迭代一个本地没有的使用云服务的功能,它是非常有帮助的。通常更新和重启比整个重新构建部署更快。
当远程客户端运行时只监控文件。如果在启动远程客户端之前你修改了文件,它将不会推送到远程服务器。
20.5.3 远程调试通道
当在远程应用上分析问题时,Java远程调试是非常有用的。遗憾的是,当你的应用部署离开你的数据中心时,远程调试并不总是能用的。如果你正在使用一个基于容器的技术例如Docker,要设置远程调试也是非常棘手的。
为了帮助解决这些限制,devtools
支持在HTTP协议上的远程调试通道。远程客户端提供一个端口为8000
的本地服务器,你可以在这上面添加一个远程调试器。一旦建立了连接,调试通道将会在HTTP上发送到远程应用上。如果你想使用一个不同的端口,你可以使用spring.devtools.remote.debug.local-port
属性。
你需要确保你的远程应用启动了并且远程调试可用。这经常可以通过配置JAVA_OPTS
来完成。例如,在云计算平台你可以添加下面的内容到你的manifest.yml
中:
---
env:
JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n"
注意你不必向
-Xrunjdwp
传递address=NNNN
选择。如果被忽略Java将会简单的选择一个随机自由的端口。
在网上调试一个远程服务可能是非常慢的,你可能需要在你的IDE中添加
timeouts
。例如,在Eclipse中你可以从Preferences…
选择Java → Debug
,并将Debugger timeout (ms)
改成更合适的值(60000
在大多数情况下都能很好工作)。
21. 将你的应用打包成产品
可执行jars
可以用来进行产品部署。当它们是自包含时,理想情况下它们也是适合云部署的。
对于其它的“production ready”功能,例如健康,审计和度量REST或JMX端点;考虑添加spring-boot-actuator
。更多细节请看第五部分,“Spring Boot Actuator: Production-ready features”。
22. 接下来读什么
现在你应该对怎么使用Spring Boot以及应该循序的一些最佳实践有了很好的理解。你可以继续学习关于Spring Boot的一些深度功能,或者你可以跳过前面,直接阅读Spring Boot “production ready”方面的内容。