10
votes

I have a problem with a Multi-Module Spring-Boot Application.

I have one Module that I use for Services, the core-Module. And one module for View-Related Classes, the web-Module. The are both in a parent-Module, where I add the dependencies, like the "spring-boot-starter" and that can be used by both modules.

Now to the problem:

I want to run the web-Module with the embedded Tomcat and have the core-Module as a dependency in the web-module.

In other Spring projects I would just include the maven-jar-plugin and create a jar of the core-Module.

The problem in this Spring-Boot project is that the maven-jar-plugin is already configured, in the "spring-boot-starter". And it needs a mainClass, which only the web-module has.

Small excerpt from the "spring-boot-starter"-POM

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>${start-class}</mainClass>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

Is there a way to package the core-Module as a JAR without needing a "start-class" in that module?

7
If you search for spring boot non executable jar, you will find Create a non-executable JAR with exclusions in the Spring Boot documentation.Andreas
@Andreas The problem is that this still needs the mainClass-Attribute. Since the configuration is in the Spring-files. I attached the Spring-Configuration in the original question.Johannes Esseling

7 Answers

7
votes

It seem like you can disable the fat-JAR from replacing the original and getting installed into the repo by configuring the spring-boot-maven-plugin.

Taken from http://docs.spring.io/spring-boot/docs/1.5.1.RELEASE/maven-plugin/examples/repackage-disable-attach.html:

By default, the repackage goal will replace the original artifact with the executable one. If you need to only deploy the original jar and yet be able to run your app with the regular file name, configure the plugin as follows:

<project>
  ...
  <build>
    ...
    <plugins>
      ...
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>1.5.1.RELEASE</version>
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
            <configuration>
              <attach>false</attach>
            </configuration>
          </execution>
        </executions>
        ...
      </plugin>
      ...
    </plugins>
    ...
  </build>
  ...
</project>

This configuration will generate two artifacts: the original one and the executable counter part produced by the repackage goal. Only the original one will be installed/deployed.

6
votes

You can just disable the spring-boot-maven plugin this way.

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <configuration>
                        <skip>true</skip>
                    </configuration>
                </execution>
            </executions>
        </plugin>
2
votes

To create simple jar update

    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>

To

    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <classifier>exec</classifier>
        </configuration>
    </plugin>

For more details please visit below Spring URL:- https://docs.spring.io/spring-boot/docs/1.1.2.RELEASE/reference/html/howto-build.html

1
votes

I have found the answer. I configured my application just like @judgingnotjudging explained. The difference was that I had put this, in the parent-POM:

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

It was preventing the default creation of JARs in the children-modules. I could resolve this problem by including this only in the web-Module.

That way Spring-Boot builds a fat-JAR from the web-Module and a simple JAR from the core-Module.

1
votes

You can simply change

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>

to

<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
1
votes

I don't know whether it's still relevant or not, however, a simple classifier needs to be configured for the spring-boot-maven-plugin -

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

This would generate two jars - one a normal one which can be included as a dependency, another as an exe jar with the "exec" word appended as a suffix - like test-0.0.1-SNAPSHOT-exec.jar and test-0.0.1-SNAPSHOT.jar

0
votes

If you're using the embedded tomcat to run your app, don't you just want a standard Spring Boot fat jar for your web app? If so, just mark your web module as dependent on your core module in the pom, and build your project.

It's there a different use case that you need the jars separated?

Are you building your modules as completely separate modules or as modules as part of a single multi-module project? The difference is in the latter, you will have a pom at the root specifying the modules. I forget the Maven syntax specifically, so my example is Gradle (Maven docs for multi-module builds are here). Sorry about that.

baseProject
|----web-module
|----core-module

baseProject's build.gradle:

project(':web-module') {
    dependencies {
        compile project(':core-module')
    }
    evaluationDependsOn(':core-module')

}

Maven has a similar structure. You should review the docs, but I believe all you need to do is specify the module order correctly in your parent pom as below and include the dependency in your web-module pom.

Parent pom:

...
<modules>
    <module>core-module</module>
    <module>web-module</module>
</modules>

web-pom:

<project ...>

<parent>
    <groupId>com.example</groupId>
    <artifactId>simple-parent</artifactId>
    <version>1.0</version>
</parent>

<artifactId>web-module</artifactId>
<packaging>war</packaging>
<name>My web-module</name>
<dependencies>

...
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>core-module</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>
...

core pom should only need to include the parent section as in the web-module above, and otherwise be the same.