我在Maven中使用SpringBoot 1.3.5。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
</parent>
和devtools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
我正在使用Intellij IDEA 2016.2,之前是2014,但存在相同问题。
我正在从Intellij Idea运行我的springboot应用程序,首先启动所有加载良好且可以正常运行的程序,我可以访问我的静态页面,我的2个Rest Controller可以工作。
2016-08-18 15:27:58.771 INFO 26626 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@469d0c02: startup date [Thu Aug 18 15:27:57 CEST 2016]; root of context hierarchy
2016-08-18 15:27:58.789 INFO 26626 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/authentication/introspect],methods=[GET]}" onto public com.myapp.models.TokenIntrospection com.myapp.resources.AuthenticationResources.introspectToken(java.lang.String)
2016-08-18 15:27:58.790 INFO 26626 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/configuration],methods=[GET]}" onto public com.myapp.models.AppConfiguration com.myapp.resources.ConfigurationResources.getConfiguration()
2016-08-18 15:27:58.792 INFO 26626 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2016-08-18 15:27:58.793 INFO 26626 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
因为仅“ Make Project”不适用于静态重新加载,所以我使用“ Rebuild Project”,有时,当应用程序重新启动时,我没有映射我的控制器,有时一个控制器丢失,有时两个都丢失。
我对此没有任何线索:(
编辑
@Morfic解决方案不起作用,因此我使用Intellij本地服务器来提供静态内容和gulp-livereload而不是spring-dev-tools。
在开发人员模式下,我只需要在JS中管理REST调用,因为REST资源位于localhost:8080上,但我的静态变量位于localhost:63342上,并在springboot中启用CORS(在属性文件中带有一个标志来启用或不启用CORS )。
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
@Value("${cors.enabled}")
private boolean corsEnabled;
@Override
public void addCorsMappings(CorsRegistry registry) {
super.addCorsMappings(registry);
if(corsEnabled) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "PUT", "POST", "DELETE", "OPTIONS")
.allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization")
.allowCredentials(true)
.maxAge(3600L);
}
}
}
因此,问题尚待解决。
最佳答案
我只是通过一个简单的hello-world服务并使用Rebuild project
几次来重现此内容,因为它仅偶尔重现一次。我的直觉是,开发工具会在IJ有机会完全清理和重建之前找出发生的更改。大概在资源发布之后以及在根据我从输出目录中看到的内容编译类之前,dev-tools会开始重新加载尚不存在的类...
按照这种假设,我查看了日志和类的时间戳,在dev-tools开始重新加载上下文的时间与将类写入磁盘的时间之间存在大约1s的差距。显然我的@PostConstruct
日志都没有出现,并且spring的autoconfig找不到我的班级...
解决方法是,可以使用trigger-file。按照链接中的建议,或在您的application.properties
文件中,将其添加为home-dir中的全局配置。另外,由于对该文件的任何更改(创建,删除,修改)都会触发重新启动,并且Rebuild project
会清除输出目录,因此您必须定义其他路径来查找该文件。因此,假设我们有一个常规的IJ spring boot运行配置,在application.properties
中有以下2个:
# name of the file to trigger a restart
spring.devtools.restart.trigger-file=restarttrigger
# where else to look for it. Also . evaluates to the app's base dir
spring.devtools.restart.additional-paths=.
...一旦看到IJ完成了构建过程,请转到应用程序根目录并添加或删除触发器文件,具体取决于该文件是否已存在,这将导致重新启动。我已经对此进行了几次测试,到目前为止没有尝试失败。下面是手动重启过程的简短视频演示:
有两种方法可以使此过程自动化。除了在IJ中定义伪像并使用后处理ant任务来生成文件之外,您还可以使用maven(已经在使用它)来生成这样的文件,但是缺点是必须使用
maven compile
代替Rebuild project
的原因,因为IJ在进行重建时不会调用maven(或者我还没有找到如何执行该操作的方法)。请在下面找到一个简单的配置based on the fact that:(注意:在Maven 2.0.5及更高版本中,绑定到阶段的多个目标将按照在POM中声明的顺序执行,但是不支持同一插件的多个实例。同一插件的多个实例被分组一起执行并在Maven 2.0.11及更高版本中排序)。
因此,the compiler plugin is by default bound to the
compile
phase,因此我们添加了一个小任务来使用application.properties
文件(或其他任何文件)生成trigger-file<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<!-- first, compile all we need -->
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<!-- then, generate the trigger-file so dev-tools will restart -->
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>compile</phase>
<configuration>
<tasks>
<copy file="${project.basedir}/src/main/resources/application.properties"
toFile="${project.basedir}/restarttrigger" overwrite="true" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
进一步更新:
查看
FileSystemWatcher.scan()
的来源,有一个do-while
循环可以解释为:尽管自上次检查以来文件系统上仍在进行更改,请等待(可配置)时间并再次验证private void scan() throws InterruptedException {
Thread.sleep(this.pollInterval - this.quietPeriod);
Map<File, FolderSnapshot> previous;
Map<File, FolderSnapshot> current = this.folders;
do {
previous = current;
current = getCurrentSnapshots();
Thread.sleep(this.quietPeriod);
}
while (isDifferent(previous, current));
if (isDifferent(this.folders, current)) {
updateSnapshots(current.values());
}
}
根据documentation,可以通过
quietPeriod
属性配置spring.devtools.restart.quiet-period
,但是也可以根据上述来源,它的值必须小于通过pollInterval
可配置的spring.devtools.restart.poll-interval
。因此,在进行设置时,我得到了不错的结果:# Amount of time (in milliseconds) to wait between polling for classpath changes.
spring.devtools.restart.poll-interval=3000
# Amount of quiet time (in milliseconds) required without any classpath changes before a restart is triggered.
spring.devtools.restart.quiet-period=2999
最后,您应该能够将这些值调整为最适合您的值。
尽管如此,如果您要修改的源是静态资源(例如FE GUI页面)并且根据您的要求,也许最好使用从其位置为它们提供服务的工具,例如节点或类似的简单http服务器...