2016-08-18 24 views
5

Używam SpringBoot 1.3.5 z maven.Springboot - DevTools - RestController nie zawsze mapowany podczas odbudowy projektu

<parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.3.5.RELEASE</version> 
</parent> 

I DevTools

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

Używam IntelliJ IDEA 2016.2, poprzednio 2014 z tym samym problemem.

Używam mojej aplikacji Springboot od Intellij Idea, pierwsze uruchomienie Wszystko jest dobrze załadowane i działa, mogę uzyskać dostęp do moich stron statycznych i moich 2 Kontrolerów Rest.

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) 

Bo po prostu „Make Project” nie działa dobrze dla przeładowania statycznej, używam „Odbuduj projekt”, a czasem, kiedy aplikacja restart, nie mam moje kontrolery odwzorowany, czasami brakuje jednego, czasami obydwaj brakuje.

nie mam żadnego pojęcia o tym :(

EDIT

@Morfic rozwiązań nie działa, więc użyłem serwer lokalny IntelliJ służyć zawartość statycznych i łykać-livereload zamiast . wiosna-dev-tools

IJ local server

miałem tylko zarządzać REST wzywa w JS, gdy jestem w trybie dev ponieważ zasoby REST są na localhost: 8080, ale moim Stati cs na localhost: 63342 i włącz CORS w moim Springboot (z flagą w pliku właściwości, aby włączyć CORS lub nie).

@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); 
     } 
    } 
} 

Więc pytanie wciąż czeka na rozwiązanie roboczej.

Odpowiedz

5

Udało mi się odtworzyć to za pomocą prostej usługi hello-world i kilkakrotnie używając Rebuild project, ponieważ odtwarza się tylko raz na jakiś czas. Moje przeczucie polega na tym, że dev-tools odkrywają, że nastąpiła zmiana zanim IJ ma szansę całkowicie wyczyścić odbudowę. Prawdopodobnie, gdy tylko zasoby zostaną opublikowane i zanim klasy zostaną skompilowane z tego, co widziałem, patrząc na katalog wyjściowy, dev-tools rozpoczyna przeładowywanie klas, które nie są jeszcze obecne ...

Postępując zgodnie z tym przypuszczeniem Spojrzałem na znaczniki czasu dzienników i klas, a między czasem, gdy narzędzia dev-tools zaczynają przeładowywać kontekst i czas, w którym moje klasy są zapisywane na dysku, istnieje luka 1s. Oczywiście żadne z moich dzienników @PostConstruct nie pojawiają się, a automatyczna konfiguracja sprężyny nie znajduje moich klas ...

Jako obejście można użyć wartości trigger-file. Dodaj ją jako globalną konfigurację w swoim katalogu domowym zgodnie z sugestią w łączu lub w pliku application.properties. Dodatkowo, ponieważ każda zmiana w tym pliku (tworzenie, usuwanie, modyfikacja) powodowałaby ponowne uruchomienie, a Rebuild project czyści katalog wyjściowy, konieczne byłoby zdefiniowanie dodatkowej ścieżki do wyszukania tego pliku. Zatem załóżmy, że mamy regularną konfigurację run IJ wiosna bagażnika, z następującym 2 w application.properties:

# 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=. 

...gdy zobaczysz, że IJ ukończył proces kompilacji, przejdź do katalogu głównego aplikacji i dodaj lub usuń plik wyzwalacza, w zależności od tego, czy już istnieje, co powinno spowodować ponowne uruchomienie. Przetestowałem to kilka razy, nie próbując do tej pory zawodzić. Poniżej krótki vide demo ponowne uruchomienie ręczne procesu:

IJ - boot dev tools manual restart

Istnieje kilka sposobów, aby zautomatyzować ten proces. Oprócz zdefiniowania artefaktu w IJ i użycia zadania post-process ant do wygenerowania pliku, możesz użyć programu maven (którego już używasz) do wygenerowania takiego pliku, ale wadą jest to, że musisz użyć maven compile zamiast Rebuild project ponieważ IJ nie będzie się powoływać na maven podczas rekonstrukcji (lub jeszcze nie wiem, jak to zrobić). Poniżej zamieszczamy prostej konfiguracji based on the fact that:

(Uwaga: W Maven 2.0.5 i powyżej, wielokrotne cele związane z fazą są wykonywane w tej samej kolejności, w jakiej zostały zgłoszone w POM, jednak wiele wystąpień ta sama wtyczka nie jest obsługiwana, wiele instancji tej samej wtyczki jest zgrupowanych w celu wykonania razem i uporządkowanych w Maven 2.0.11 i nowszych).

Jako takie, the compiler plugin is by default bound to the compile phase, więc dodamy małe zadanie do generowania trigger-file pomocą pliku application.properties (lub czegokolwiek innego)

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

Dalsza zmiana:

Szukacie w źródłach FileSystemWatcher.scan() znajduje się pętla do-while, która może być interpretowana jako: natomiast nadal istnieją zmian zachodzących w systemie plików od poprzedniego sprawdzianu, odczekaj (konfigurowalne) czas i sprawdzić ponownie

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()); 
    } 
} 

Jak na documentation The quietPeriod jest konfigurowany za pomocą właściwości spring.devtools.restart.quiet-period, ale również zgodnie ze źródłem wymienionym powyżej musi to być wartość mniejsza niż pollInterval konfigurowalna przez spring.devtools.restart.poll-interval. Tak więc, zabawy z ustawieniami, mam przyzwoity wynik z:

# 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 

W końcu, należy być w stanie dostosować się do tych wartości, co najbardziej Ci odpowiada. Niemniej jednak, jeśli modyfikowane źródła są zasobami statycznymi, takimi jak strony GUI FE i zależnie od wymagań, być może lepiej jest użyć narzędzia, które obsługuje je z ich lokalizacji, na przykład węzła lub podobnego prostego serwera http. ...

+0

Wahou bardzo ładne wyjaśnienie, dzięki. Jak zapewne domyślacie się, nie mogę odtworzyć/zmodyfikować pliku za każdym razem, gdy chcę przeładować mój projekt :( I nie wyjaśniłem tego, ale używam Springboot z 2 kontrolerami odpoczynku i muszę często odbudowywać pliki statyczne. – Titmael

+0

I próbował tego, ale nie zmienił problemu: http: // stackoverflow.com/a/36839483/1243048 – Titmael

+1

@Titmael moja sugestia jest najprostsza i najbezpieczniejsza z możliwych, ponieważ wszystko powinno być już skompilowane i dostępne podczas tworzenia/edycji/usuwania pliku. Niestety z tego, co widziałem, nie jest to możliwe za pośrednictwem Mavent, ponieważ IJ nie wywołuje go dla funkcji budowania, ale prawdopodobnie może być nieco zautomatyzowane, aby utworzyć artefakt na kompilacji i skopiować plik wyzwalacza za pomocą docelowego Anta, jeśli Jestem zainteresowany. – Morfic

0

Ta część @ odpowiedź Morfic pracował wielki dla mnie:

# 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