2016-08-18 39 views
5

我使用SpringBoot 1.3.5和maven。SpringBoot - DevTools - RestController在重建项目时并不总是映射

<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休息控制器的工作。

2016-08-18 15:27:58.771 INFO 26626 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot[email protected]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) 

因为简单的“做项目”不适用于静态重载工作得很好,我用“重建工程”,有时,当应用程序重新启动,我没有我的控制器映射,有时一个缺少,有时两人都失踪了。

我没有这个:(

编辑

@Morfic解决没有工作的任何线索,所以我用的IntelliJ本地服务器提供静态内容,并吞掉,livereload代替。弹簧开发工具

IJ local server

我不得不管理JS调用REST当我在开发模式,因为REST资源在localhost:8080,但我为static cs on 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); 
     } 
    } 
} 

所以问题仍然悬而未决的工作解决方案。

回答

5

我刚刚设法通过一个简单的hello-world服务重复此操作,并且使用Rebuild project几次,因为它只能在一段时间内重现一次。我的直觉是,在IJ有机会彻底清理&重建之前,开发工具发现有变化。可能一旦资源发布,并且在从我看到的输出目录编译类之前,开发工具开始重新加载尚未存在的类 ...

按照这个假设,我查看了日志和类的时间戳,开始重新加载上下文的时间与我的类写入磁盘的时间之间存在大约1秒的差距。很明显,我的@PostConstruct日志中没有一个出现,并且spring的autoconfig没有找到我的类...

作为解决方法,您可以使用trigger-file。您可以按照链接中的建议或在您的application.properties文件中将其作为全局配置添加到您的主目录中。此外,由于对该文件的任何更改(创建,删除,修改)都会触发重新启动,并且会清除输出目录,所以您必须定义一个额外的路径来查找此文件。因此,假设我们有一个常规IJ弹簧引导运行配置,在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 - boot dev tools manual restart

有一对夫妇的方式来自动完成这个过程。除了在IJ中定义artefact并使用后期处理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文件(或任何其他)

<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> 

进一步更新生成trigger-file

展望在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服务器...

+0

Wahou很不错的解释,谢谢。 正如你可能猜测,我不能每次我想重新加载我的项目时播放文件创建/修改:( 而我没有解释它,但我用2个其余控制器springboot,需要经常重建静态文件 – Titmael

+0

我试过这个,但没有改变问题:http:// stackoverflow。com/a/36839483/1243048 – Titmael

+1

@Titmael我的建议是最简单和最安全的,因为在创建/编辑/删除文件时,所有内容都应该已经编译并可用。不幸的是,从我看到的它不可能通过Mavent,因为IJ并没有为构建过程调用它,但它可能有点自动化,在构建时创建一个artefact,如果你有一个后期制作的Ant目标复制触发器文件'感兴趣。 – Morfic

0

的@我Morfic的回答真是棒极了这部分:

# 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