14

Reload of multi-module maven project changes


Setting

Imagine a multi-module maven-project. The project structure is:

pom.xml //parentpom
   |
  pom.xml //submodule_1
   |
  pom.xml //submodule_2
   .
   .
   .
  pom.xml //submodule_7

For example submodule_5 has submodule_6 and submodule_7 as dependencies. The submodule_5 can be build to construct a War-file which can be deployed. Spring-Boot-Devtools provide the feature of automatic-restart whenever there is a change to submodule_5 it's classpath.

Whenever the application is run using:

mvn spring-boot:run

And changes are made to submodule_5 (depending on which IDE you use the classpath get changed. (for Eclipse automaticaly / for InteliJ when pressing Ctrl+F9)) spring-boot automaticaly restarts the application and changes are added. Changes which happen to submodule_6 or submodule_7 don't trigger the automatic restart.


Questions

  1. Is there a way to make it so that whenever you make changes in submodule_6 or submodule_7 to have them force a restart and there-for apply the changes?
  2. Spring-boot-devtools uses two classloaders: "The Base Classloader" & "The Restart Classloader". Is it so that on initial start of the application submodule_6 and submodule_7 get added to "The Base Classloader" whilst submodle_5 is kept in the "The Restart Classloader"? Making it so that whenever submodule_5 forces a restart it uses the versions of submodule_6 and submodule_7 out of "The Base Classloader"?
mx0
  • 6,445
  • 12
  • 49
  • 54
Nodon Darkeye
  • 532
  • 5
  • 20
  • Answer on StackOverflow doesn't work like this, when someone give you the correct answer you can just check that and it'll appear on top with a "correct mark". See other questions – Paolo Forgia Aug 17 '16 at 13:40

3 Answers3

7

You may specify additional folders to be watched by spring-boot-devtools, in application.properties:

spring.devtools.restart.additional-paths=../submodule_6,../submodule_7

See Spring's documentation on using-boot-devtools-restart-additional-paths.

alexbt
  • 16,415
  • 6
  • 78
  • 87
  • I came across this aswell. My question for this would be if there is a way to do this with annotations or something like that. And if the restart is triggered I assume it than only depends on how well maven ect. is configured to also build submodule_6 and submodule_7 whenever submodule_5 has restarted? – Nodon Darkeye Aug 17 '16 at 19:17
  • 2
    Just tried it and it works! I believe the reason it works, is because spring-boot:run read the compiled classes & resources directly from the projects' folders (rather than the generated artifacts). I added another's module folder to the watched folder. I modified a class in this other module, the application restarted and I could see the modification. – alexbt Aug 17 '16 at 20:20
  • 2
    I also tried it and for me the restart happens, but the changes are not applied. I've read that working from commandline and from within the IDE might differ. May I ask how you ran your application, I did it from the commandline. It detected that changes were made. It retarted the application, but it did not apply the changes. Maybe it works differently whenever you're working within an IDE. – Nodon Darkeye Aug 18 '16 at 08:53
  • I did it from Eclipse, which had time to rebuild the modified .java into *.class before the restart happens – alexbt Aug 18 '16 at 10:55
5

To fix this problem I started running the application from within InteliJ. without having to add.

spring.devtools.restart.additional-paths=../submodule_6,../submodule_7

IntelliJ and spring-boot seem to work together very wel. The reason it was not working for me in the first place was because I was working from the commandline at first.

Difference between commandline and IDE

So spring-boot-devtools uses two classloaders to load an application. Jars will be loaded ones in the "Base classloader", your application will be loaded in the "restart classloader". This last classloader will restart everytime there is a change on the classpath.

Whenever running submodule_5 from the commandline, it will build the submodule_6 and submodule_7 and add the jars to the build of submodule_5. Whenever changes are made in submodule_6 and submodule_7 spring-boot won't even notice since it's only watching submodule_5 and has the jars it needs. Even if you would specifically tell it to also watch those submodules, it still won't rebuild those, it'll just keep using the jars it already has loaded in the "base classloader" (This is my assumption, I'm not 100% certain of the way it works).

Whenever running submodule_5 from the IDE, it won't create the jar of the submodule_6 and submodule_7. It will just use their classpath. This makes it so that changes in your intire project's classpath (all submodules) will trigger the automatic restart and the changes will be applied.

EXTRA

Whenever running from the IDE changes to resources like html-files, css-files, xml-files . . . won't trigger a restart since this is not a change in the classpath. But the changes will still be visible.

Nodon Darkeye
  • 532
  • 5
  • 20
1

I tried with spring.devtools.restart.additional-paths and in any case it is useless : source change restart the application but helpless because the application doesn't have the target/classes of modules during its execution.

With spring-boot:run executed on quite recent IntelliJ versions : it works out of the box.

With spring-boot:run executed on command line : there are at least two cases.

Case 1) we want to execute spring-boot:run from the module that has the spring boot main class (submodule_5 in the op question). We need to add in the plugin configuration of its pom.xml the additional classpaths of compiled classes that we want that spring-boot plugin be aware it :

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>                    
                <folders>
                    <folder>                            
                           ../submodule_6/target/classes
                    </folder>
                    <folder>                            
                           ../submodule_7/target/classes
                    </folder>
                </folders>
            </configuration>
        </plugin>
    </plugins>
</build>

Case 2) we want to execute spring-boot:run from the parent-module.
It works only with pom multi-modules that are also parent of modules.
We need to do two changes :
First, add the spring boot plugin declaration with flag skip in the parent pom :

 `<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>

    </plugins>
 </build>`

Then add in the pom.xml of the module that has the spring boot main class (submodule_5 in the op question) :

 <build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <skip>false</skip>                 
            </configuration>
        </plugin>
    </plugins>
</build>

We can now start the application from the parent pom with :

mvn -pl submodule_5 -am spring-boot:run

FYI these maven flags specify to apply the goal on submodule_5 after applied that on its dependencies (whereas the skip flag in the multi/parent pom.xml).

davidxxx
  • 125,838
  • 23
  • 214
  • 215