开发者工具,可以在开发SpringBoot的时候,自动的实现实时开发特性。使用过程需要引入如下的依赖:

对于maven来说:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

对于Gradle来说:

dependencies {
    developmentOnly("org.springframework.boot:spring-boot-devtools")
}

当进行全量打包(fully packaged)的时候, Developer Tools会自动的被禁用。比如,当你用 java -jar 或者制定了类加载器的时候,则会被当成是 生产应用 (production application)。生产环境上,通常不允许启用devTools工具,因为这是一个严重的安全问题。如果想启用 Devloper Tools,需要配置 spring.devtools.restart.enabled 系统属性为 true

默认属性(Property Defaults)

需要第三方的依赖都会使用缓存来提高应用性能。例如,Spring 提供的 thymeleaf3 会缓存编译模版。虽然缓存在生产环境上很有用,但是在实际开发的过程中,可能会导致更改无法及时生效,所以默认情况下,devtools是禁用了缓存选项的

如果你在开发Spring MVC 和 Spring WebFlux的应用的时候,DevTools工具可以支持对Web请求启用DEBUG级别的日志(可以给出更详尽的日志记录信息,可能包括一些潜在的敏感信息)。设置方法为打开 spring.mvc.log-request-detailsspring.codec.log-request-details 配置属性。

如果你不想启用默认的属性,你可以在appplication.properties中设置 sprint.devtools.add-properties=false

自动重启(restart)

配置了spring-boot-devtools的应用,会去监控classpath上的文件修改,如果有修改,就会出发应用的重启。但是有些时候,对于一些静态资源文件(例如,asset和view template)的修改,则并不需要重启应用。

当DevTools监视类路径资源时,触发重启的唯一方法是更新类路径(classpath)。导致类路径更新的方式取决于您使用的IDE触发classpath更改的方式。

只要forking启用,则可以通过构建管理插件(gradle或maven)来启动应用程序。默认情况下,Gradle或Maven会Fork这个应用进程。

通常情况下,自动重启(Automatic restart)会配合LiveReload使用。 查看 LiveReload 章节 获取更多信息。如果使用 JRebel,则自动重启会禁用动态类的加载功能。其它的DevTools特性(例如 LiveReload和Property重载)还是依旧有效。

在restart的期间,DevTools根据应用的context的shutdown hook来选择关闭应用。如果你设置了SpringApplication.setRegisterShutdownHook(false)来禁用shutdown hook,则会导致自动重启不能正常工作。

DevTools需要去自定义 ApplicationContext 使用的 ResourceLoader。如果你的应用程序已经提供了一个,则会在此基础上包装一份。不支持直接重写在 ApplicationContext 上的 getResource 方法。

重新启动 VS 重新加载的

SpringBoot 提供的重启技术通过两个类加载器来工作。不变类(例如从第三方Jars中得到的)会被加载到 base 类加载器中。可变类(例如,正在开发编译出来的类)会被加载到 restart 类加载器中。当一个应用重启的时候,这个 restart 类加载器将会被丢弃,然后重新新建一个新的。这种方式会比传统的 cold start(冷启动)快一些,因为没有 base 类加载器的重建工作。

如果你任然觉得重启速度不够快,那么可以尝试考虑使用类似于 JRebel重新加载技术(reloading technologies)。这些方法通过在加载类时重写类来使其更易于重新加载。

条件评估增量(审计日志)

默认情况下,每次应用程序重新启动时,都会记录一个报告,其中显示了条件评估增量。可以粗略的认为就是审计日志。这个报告里面包含了你的自动配置的改变,(例如增加或者移除了Spring Bean 和设置的配置属性)。

如下设置可以禁用这种报告的记录:

spring.devtools.restart.log-condition-evaluation-delta=false
排除资源文件(Excluding Resources)

一些资源文件,不希望能够自动触发程序的重启。例如,Thymeleaf 模版的编写。默认情况下,更改/ META-INF / maven,/ META-INF / resources,/ resources,/ static,/ public或/ templates中的资源不会触发重新启动,但会触发实时重新加载(live reload)。如果你想自定义 排除一些文件,可以使用 spring.devtools.restart.exclude属性 。例如,只想排除 /static/public ,你可以如下设置:

spring.devtools.restart.exclude=static/**,public/**

如果你想保留默认的,但增加一些额外的自定义配置,那么你可以设置在 spring.devtools.restart.additional-exclude 属性中。

监控额外的路径

如果你想在修改非类路径下的文件的时候,自动触发程序的重启,那么你可以配置 spring.devtools.restart.additional-paths 属性,配置一些额外的路径。可以使用前面所述的spring.devtools.restart.exclude属性来控制其他路径下的更改是触发完全重启还是实时重新加载。

禁用重启(Disabling Restart)

如果你不想使用restart特性,你可以通过设置 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);
}
使用触发文件(Using a Trigger File)

如果使用的IDE不断的编译更改的文件,则您可能需要仅在特定的时机触发重新启动。为此,您可以使用“触发文件”,这是一个特殊文件,当您要实际触发重新启动检查时必须对其(触发文件)进行修改。

需要设置 spring.devtools.restart.trigger-file 属性来设置触发文件名称。触发文件,必须要包含在类路径上。例如,你的项目结构如下:

src
+- main
   +- resources
      +- .reloadtrigger

那么你的 触发文件属性可以设置成如下

spring.devtools.restart.trigger-file=.reloadtrigger

只有当 src/main/resources/.reloadtrigger 文件更新的时候,才会触发程序的重新启动。

触发文件可以设置为全局生效,可以参考如下文档 global setting

一些IDEs 有些特性用来实现不必手动的更新触发文件的功能。对于IDEA可以参考文档 instructions in their documentation.

自定义重启类加载器

正如前面走章节所诉,重启功能依赖两个类加载器。对于大多数的应用,这种方案可以做的很好。但是,又些情况可能会导致类加载器的问题。

默认情况下,IDE中任何打开的项目都使用“restart”类加载器加载,而任何常规.jar文件都使用“base”类加载器加载。如果你使用的是多项目模块,但是并不是所有的模块都被导入到了IDE中,那么你就需要去自定义一些事情。为了实现如此,你需要创建一个 META-INF/spring-devtools.properties 文件。该属性文件内的属性,以 restart.excluderestart.include 开头。其中 include 元素中列出来的项目,是会被上拉到 restaret 类加载器中,而 exclude 属性中列举出来的类,是会被下推到 base 类加载器中。属性值是一个类路径上的正则表达式。如下:

restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\\.]+\\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\\.]+\\.jar

所有的Key值必须唯一

已知的限制(Known Limitations)

Restart functionality does not work well with objects that are deserialized by using a standard ObjectInputStream. If you need to deserialize data, you may need to use Spring’s ConfigurableObjectInputStream in combination with Thread.currentThread().getContextClassLoader().

Unfortunately, several third-party libraries deserialize without considering the context classloader. If you find such a problem, you need to request a fix with the original authors.

实时加载(LiveReload)

spring-boot-devtools 模块包含了一个嵌入的 LiveReload 服务器,它可以实现当资源文件更改的时候,自动的去触发浏览器刷新。可从livereload.com免费获得适用于Chrome,Firefox和Safari的LiveReload浏览器插件。

如果 你想禁用 LiveReload 服务器的启动,可以设置 spring.devtools.livereload.enabled 属性为 false。

一次只能运行一台LiveReload服务器。在启动应用程序之前,请确保没有其他LiveReload服务器正在运行。如果从IDE启动多个应用程序,则只有第一个具有LiveReload生效。

要在文件更改时触发LiveReload,必须启用自动重启(Automatic Restart )。

全局设置

如果你想全局设置 devtools的设置,你可以在 $HOME/.config/spring-boot 目录下的:

  1. spring-boot-devtools.properties
  2. spring-boot-devtools.yaml
  3. spring-boot-devtools.yml

的任何文件(之一)中增加你想配置的属性,在文件中定义的属性会对你本机上的所有 springboot程序生效。例如,你想配置重启时候,总是使用触发文件(trigger file),你可以在全局配置中,添加如下属性:

spring.devtools.restart.trigger-file=.reloadtrigger

如果在 $HOME/.config/spring-boot中找不到devtools配置文件,则在$HOME目录的根目录中搜索是否存在.spring-boot-devtools.properties文件。这个允许你去共享全局的 devtools 的配置。该路径是哪些不支持 $HOME/.config/spring-boot 的老版本中。

devtools属性/ yaml文件中不支持 Profiles 配置。

设置文件系统监控

FileSystemWatcher 主要用于基于某一个时间间隔下轮训校验class的更改,然后等待某一段时间用来确认没有其它的更改。因为Springboot有些时候,会依赖于IDE的编译和复制class文件,所以可能会导致某些更改在重启应用之后没有及时生效。这些时候,可以通过调整 spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period 参数来满足开发需求:

# 确定轮训class文件更改的时间
spring.devtools.restart.poll-interval=2s
# 确定轮训到class文件更改后的观察时间
spring.devtools.restart.quiet-period=1s

远端应用(Remote Application)

DevTools工具并不仅限于本地应用,也有一些特性可以用于远端运行的应用。虽然在生产环境上使用DevTools工具是一个安全问题,但是在确保安全的环境也还是可以使用。

首先确保打出来的jar包包含了 DevTools 依赖。然后设置 spring.devtools.remote.secret 属性,属性值就是一个密钥(确保够复杂,不容易被猜测和暴力破解)。

Remote devtools主要由两部分提供:一个服务器端(用于接受连接)和一个客户端(通常运行的本地IDE)。当设置了 spring.devtools.remote.secrect 属性之后,服务端会自动的运行。但是客户端组件还是需要手动的启动。

运行客户端应用(Running the Remote Client Application)

客户端应用被设计成了在 IDE 中运行。您需要使用与您连接到的远程项目相同的类路径来运行org.springframework.boot.devtools.RemoteSpringApplication。这个应用需要的必要参数就是远程服务器的连接URL

例如,你使用了Eclipse或STS,并且你的项目命名为 my-app,然后你将它部署到了 Clouud Foundry。你需要做以下的一些事情。

  1. Run 菜单中,选择 Run Configurations……
  2. 新建一个 New Application 启动属性
  3. 浏览这个 my-app 项目
  4. 使用 org.springframework.boot.devtools.RemoteSpringApplication 作为主类
  5. 添加 https://myapp.cfapps.ioProgram arguments

正在运行的远程客户端,可能看到如下的消息:

  .   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote :: 2.4.0

2015-06-10 18:25:06.632  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code)
2015-06-10 18:25:06.671  INFO 14938 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043  WARN 14938 --- [           main] o.s.b.d.r.c.RemoteClientConfiguration    : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074  INFO 14938 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2015-06-10 18:25:07.130  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)

因为远程客户端使用与真实应用程序相同的类路径,所以它可以直接读取应用程序属性。这就是读取spring.devtools.remote.secret属性并将其传递给服务器进行身份验证的方式。

始终建议使用https://作为连接协议,以便对通信进行加密并且不能截获密码。

如果您需要使用代理访问远程应用程序,请配置 spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port 属性.

远端更新

远程客户端以与本地重启(local restart)相同的方式监视应用程序类路径中的更改。**任何更新的资源都将推送到远程应用程序,并且(如果需要)触发重新启动。**最大的优势就是快速的就能够将特性更新到线上,本地也可以使用到云服务产品。

需要注意的是,如果本地开发的很慢,可能会导致静默期(Predefined Quiet)中定义的时间间隔不够,程序将本地的修改分成了多个批次(batchs)。而远端应用因为第一次批次的修改到来了而进行重启,在重启期间导致远端服务器无法接受第二个批次的修改数据。可以通过修改轮训时间间隔 spring.devtools.restart.poll-interval 和静默期间隔 spring.devtools.restart.quiet-period 参数来适应自己的开发节奏。

参考文档:

  1. Using Spring Boot
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐