关于Spring Loaded
最近在倒腾Spring全家桶的应用,在阅读官方文档19.5节的时候无意中发现了了一个被称作hot-swapping的技术,这类在java5代理技术出现之后出现的字节码热交换技术其实也不是新鲜事,但是对于spring这样application动不动启动10来秒的框架如若使用热交换对开发效率无疑有一个质的提升,于是就根据文档踩了下坑。
引入
Maven
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies>
|
Gradle
如果作为gradle引入的话要稍微麻烦一点
首先需要加入依赖
dependencies { compile "org.springframework.boot:spring-boot-gradle-plugin" compile 'org.springframework:springloaded' } idea { module { inheritOutputDirs = false outputDir = file("$buildDir/classes/main/") } } buildscript { repositories { jcenter() } }
|
运行时加入VM参数
-javaagent:{path_to_jar}\springloaded-1.2.5.RELEASE.jar -noverify
|
如果想完成静态资源静态替换,则需要在application.properties中加入
spring.freemarker.cache=false //此为freemarker配置,其他模版引擎请参照文档
|
完成上述配置之后便可以使用热交换插件了
使用
1.使用调试模式运行Spring boot application,笔者使用的IDEA为图示按钮
2.修改字节码后使用上图左侧make按钮(默认快捷键alt+f9)编译新的项目,由于插件的存在,会自动将output中的代码进行热替换而无需重新启动整个application。
3.模版引擎在make之后也能马上变化(非Spring Loaded特性,无论是否配置Spring Loaded,静态资源替换在make候会自动生效)
坑
1.如果是一般类/方法修改热替换,代理技术会起到很好的作用,但是需要注意我是我们使用的是Ioc容器,如springmvc的注解映射依赖于启动时扫描,假如替换了映射的类,springmvc并不知道这一变化,而会寻找之前的方法,这时候就会抛出找不到方法异常
简单看下示例
@RequestMapping("/finduser/{username}") @ResponseBody public User findUser(@PathVariable String username){ User user=userService.findByUsername(username); return user; }
|
此时我们如果把该方法改为
@RequestMapping("/finduser/{username}") @ResponseBody public String findUser(@PathVariable String username){ return "ok"; }
|
虽然字节码被热替换了,但是框架抛出了异常
java.lang.NoSuchMethodError: {packagename}.UserController.findUser(Ljava/lang/String;)L{packagename}/domain/User;
|
总结
对于普通类的修改,spring loaded确实是是一个很好的工具,整个make/替换过程短暂极大提升了开发效率,但对于部分ioc容器,依旧需要重启appliction才能完全看到修改后的代码。