Spring Boot参考文档(12)开发者工具

来源:互联网 发布:java写入日志文件 编辑:程序博客网 时间:2024/06/05 04:14

原文链接:http://www.dubby.cn/detail.html?id=8725

Spring Boot包含一些额外的工具,让我们在开发时可以更愉快一些。项目中可以加入spring-boot-devtools模块,为我们的应用带来一些额外的开发时功能。为了添加这个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")}

当你运行一个打包成jar的应用时,开发工具的功能会自动禁止。如果你的应用以java -jar命令启动,那么Spring Boot认为这是一个生产环境的应用。把devtools标志位optional(可选的)是一个最佳实践,这样可以防止其他项目依赖你的项目是也用到了devtools。Gradle不支持optional,所以你或许要参考propdeps-plugin。

默认情况下打包时是不会包含devtools的。如果你希望使用某个特定的远程功能,你需要自己去关闭excludeDevtools属性,来包含devtools。这个属性对Maven和Gradle都是支持的。

默认属性

Spring Boot支持的很多库都使用cache来提高性能。例如,模板引擎会缓存编译过的模板,来避免重复的转换文件。同样的,对于静态文件,Spring MVC可以缓存HTTP返回给response的headers。

虽然在生产环境中缓存有很多好处,但是在开发时却有可能起反作用。例如,不能及时的看到你的一些代码变动。所以,spring-boot-devtools默认是关闭缓存功能的。

缓存配置通常是在application.properties配置的。例如,Thymeleaf 有spring.thymeleaf.cache属性。不需要手动的设置这些属性配置,spring-boot-devtools会自动给我做出合适的配置。

想要获得一个完整的属性列表,参考DevToolsPropertyDefaultsPostProcessor。

自动化(无意识)重启

应用如果使用了spring-boot-devtools,那么当classpath中的class发生改变时,他会自动重启。这个功能是很有用的,因为我们在使用IDE编写代码时,可以很快的得到一个反馈。默认情况下,classpath中任何一个入口都意味着,对这个文件夹的改变有一个的监控。注意,静态文件和视图模板的改变不需要重启应用。

触发重启

当DevTools监控classpath的资源时,只有classpath发生改变时,才会触发重启。你的IDE会做到这一点。在Eclipse中,保存一个改变的文件会导致重新编译成一个class,这会触发重启。在IntelliJ IDEA中,构建(Build -> Make Project)也会起到同样的效果。

通过Maven和Gradle的插件启动时,只要你的classpath中包含DevTools,也会触发重启。

自动重启可以和LiveReload搭配使用。但是如果你使用的是JRebel ,那么自动重启就会失效。

在重启时,DevTools依赖于应用的shutdown hook(译者注:hook是钩子,变成常见的一种概念)。如果你禁用了shutdown hook(SpringApplication.setRegisterShutdownHook(false)),那么重启也会失效了。

在监控classpath改变时,DevTools会自动忽略这几个项目spring-boot, spring-boot-devtools, spring-boot-autoconfigure, spring-boot-actuator, 和 spring-boot-starter

Restart vs Reload

Spring Boot提供的重启技术,是使用两个classloader实现的。一些不变得class(例如第三方库)会被一个”基本classloader”加载。那些你直接开发的class会被”重启classloader”加载。当应用重启时,这个”重启classloader”会被销毁,然后重新创建一个”重启classloader”。这种方式可以让重启变得比”冷重启”快很多,因为第三方的”基本classloader”是已经存在的。

如果你发现重启不是快到让你满意,甚至起了反作用,那你可以考虑使用reload技术,例如JRebel。当reload时,会重写class保证可以reload。Spring Loader提供了另外一种选择,但是,很多框架并不支持,而且也没有商业支持。

除外的资源

某些特定的资源的改变不会触发重启。例如,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.enabled属性。大部分情况下,你可以在application.properties里设置这个属性(这个也会启动一个”重启classloader”,但是不会监控文件的改变了)。

如果你希望完全禁止重启,例如,他对某个特定的库不支持,你需要在调用SpringApplication.run(…)前设置一个System属性:

public static void main(String[] args) {    System.setProperty("spring.devtools.restart.enabled", "false");    SpringApplication.run(MyApp.class, args);}

使用一个触发文件

如果你使用的时IDE,那你有可能无时无刻不在重启。也许你只想要在某个特定的时间重启。这样你可以使用”触发文件”,当你改变这个文件时,就会触发重启。改变这个文件只会让触发器查看是不是真的有必要重启,如果不得不重启,那”重启classloader”就会真的重启。这个触发文件你可以手动修改,也可以通过IDE插件修改。

为了使用触发文件,你需要设置spring.devtools.restart.trigger-file属性。

你可以把spring.devtools.restart.trigger-file设置成全局属性,这样你所有的项目都会监控一个文件了。

自定义 “重启classloader”

上面介绍了重启的实现,我们知道重启依赖两个classloader。大部分情况下,这可以很好的工作,但是有的时候,这个歌会引发classloader的问题。

默认情况下,所有的你的项目打开的文件都会使用”重启classloader”来加载,任何.jar都会用”基本classloader”加载。如果你在多module项目下工作过,并不是每一个module都会被你的项目使用,这种情况下,你需要自己来自定义些东西,来使得重启更为高效。你可以创建META-INF/spring-devtools.properties文件。

META-INF/spring-devtools.properties文件可以包含以restart.exclude.restart.include.为前缀的属性。include是那些应该被拉进”重启classloader”的类,exclude指的是那些不会被拉进”重启classloader”的类。之是正则表达式。

例如:

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

所有属性的key必须是唯一的。只要属性的前缀是restart.include.或者restart.exclude.就都会被处理。

classpath下所有的META-INF/spring-devtools.properties都会被加载。你可以在你的项目内部打包,或者其他项目依赖你的项目打包,都可以生效。

已知的局限性

重启机制对于那些被ObjectInputStream反序列化的对象是无能为力的。如果你需要反序列化对象,你或许可以尝试使用ConfigurableObjectInputStreamThread.currentThread().getContextClassLoader()配合使用。

不幸的是,有的第三方库直接反序列化的,而不考虑classloader。如果你发现这个问题,你需要去通知作者来fix这个问题。

LiveReload

spring-boot-devtools包含一个LiveReload服务器(修改源码后,帮你刷新浏览器),帮你触发重启后刷新浏览器,支持Chrome。Firefox和Safari。

如果你不想要这个LiveReload服务器,你可以设置spring.devtools.livereload.enabled为false。

一次只能运行一个LiveReload服务器。在启动应用时,确保没有其他的项目在使用LiveReload服务器。如果你用IDE启动多个项目,那么只有第一个的LiveReload服务器会生效。

全局设置

你可以在你的$HOME目录下添加.spring-boot-devtools.properties文件来实现全局设置。这个文件里的任何属性都会被应用到这个机器上的所有开启了devtools的Spring Boot应用。例如,设置一个触发重启的文件,你可以这样修改:

~/.spring-boot-devtools.properties

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

远程应用

Spring Boot的开发者工具不仅仅局限于本地开发。你也可以应用在远程应用上。远程应用是可选的。如果你想开启,你需要把devtools的包加到你的打包的jar中:

<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.devtools.remote.secret,服务端就会自动开启。客户端需要你手动来开启。

运行远程应用的客户端

远程应用的客户端被设计成在你的IDE中运行。你需要在拥有和你的远程应用相同的classpath的前提下,运行org.springframework.boot.devtools.RemoteSpringApplication。这个application的参数就是你要连接的远程应用的URL。

例如,如果你用的是Eclipse或者STS,你有一个项目叫my-app,你已经部署在云平台上了,你需要这么做:

  • Run菜单选择Run Configurations…
  • 创建一个Java Application的启动配置
  • 使用org.springframework.boot.devtools.RemoteSpringApplication作为启动类
  • https://myapp.cfapps.io作为程序的参数(这个URL是你真正的URL)

一个启动的远程应用是这样的:

  .   ____          _                                              __ _ _ /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \ \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / / =========|_|==============|___/===================================/_/_/_/ :: Spring Boot Remote :: 1.5.3.RELEASE2015-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-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/spring-boot-samples/spring-boot-sample-devtools)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 hierarchy2015-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 357292015-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)

因为classpath是一样的,所以可以直接读取真实的配置属性。这就是spring.devtools.remote.secret发挥作用的时候了,Spring Boot会用这个来认证。

建议使用https://来连接,这样密码会被加密,不会被拦截。

如果你有一个代理服务器,你需要设置spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port这两个属性。

远程更新

客户端会监控你的classpath,和本地重启的监控一样。任何资源更新都会被推送到远程服务器上,远程应用再判断是否触发了重启。如果你在一个云服务器上做迭代,这样会很有用。一般来说,字节更新远程应用,会比你本地打包再发布要快狠多。

资源监控的前提是你启动了本地客户端,如果你在启动之前修改了文件,这个变化是不会推送到远程应用的。

远程debug通道

在定位和解决问题时,Java远程调试是很有用的。不幸的是,如果你的应用部署在异地,远程debug往往不是很容易实现。而且,如果你使用了类似Docker的容器,也会给远程debug增加难度。

为了解决这么多困难,Spring Boot支持在HTTP层面的debug通道。远程应用汇提供8000端口来作为debug端口。一旦连接建立,debug信号就会通过HTTP传输给远程服务器。你可以设置spring.devtools.remote.debug.local-port来改变默认端口。

你需要首先确保你的远程应用启动时已经开启了debug模式。一般来说,可以设置JAVA_OPTS。例如,如果你使用的是Cloud Foundry你可以在manifest.yml加入:

---    env:        JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n"

注意,没有必要给-Xrunjdwp加上address=NNNN的配置。如果不配置,Java会随机选择一个空闲的端口。

远程debug是很慢的,所以你最好设置好debug的超时时间(一般来说60000是足够了)。

如果你使用IntelliJ IDEA来调试远程应用,你一定要把所有断点设置成悬挂线程,而不是悬挂JVM。默认情况,IDEA是悬挂JVM的。这个会造成很大的影响,因为你的session会被冻结。参考IDEA-165769。

0 0
原创粉丝点击