Maven multimodule project with Spring Boot
I will try to be close to real task here. Lets say we have RestAPI web application, command line application for manupulating with secure data (installation, initial user creation, etc). Both will work with same data, so we need 3rd project which will be linked as dependency from cli and web.
Folder structure
rootProject
-> datalib
-> cli
-> web
Project types
rootProject/pom.xml
should refer to type pom
. Type pom
means that rootProject is just a place for references from the other projects. There is no target
, no .jar files for the rooProject, it’s used by subprojects (aka modules) to find each other, plus if you have same dependensy in different subprojects you can only mention them once in rootProject/pom.xml
.
All subprojects / modules will have type jar
in our case. So build will produce .jar files.
Linking everything together
Package name
Package name aka namespace has to be the same for rootProject and submodules.
GroupID
project/groupId
also has to be the same for rootProject and submodules, like this:
<project ..>
...
<groupId>org.rootProject</groupId>
...
</project>
RootProject has to link to all modules:
file: rootProject/pom.xml
<project ..>
...
<!-- modules -->
<modules>
<module>web</module>
<module>cli</module>
<module>datalib</module>
</modules>
Modules has to link rootProject as a parent
files: rootProject/cli/pom.xml, rootProject/web/pom.xml, rootProject/datalib/pom.xml
<project>
...
<parent>
<artifactId>rootProject</artifactId>
<groupId>org.rootProject</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
...
</project>
But wait! Spring has to be parent project too!
Obviously, we can’t have 2 parants for the module. So we have to move spring reference to rootProject/pom.xml.
<project>
<groupId>org.rootProject</groupId>
<artifactId>rootProject</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>rootProject</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
...
</project>
Hierarhy is like this:
- Spring Boot
-
- rootProject
-
-
- web
-
-
-
- cli
-
-
-
- datalib
-
Using one module from another
Right now, our modules know about rootProject but they do not know about each other. Datalib will be used in cli and web, so we need to add dependency:
files: rootProject/cli/pom.xml, rootProject/web/pom.xml
<project>
...
<dependencies>
<dependency>
<groupId>org.rootProject</groupId>
<artifactId>datalib</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
...
</dependencies>
...
</project>
Build commands
That’s a bit counterintuitive. You need 2 commands:
From rootProject/
mvn clean install
will build all projects in correct order and place relusting .jar files in local storage, where java will be able to find them. To run maven commands on subproject, you need to use -pl and -am, like this:
mvn -am -pl web spring-boot:run
or
mvn -am -pl cli test
-am
means “take dependencies into consideration” without that you might get symbol not found
error.
-pl
just short for –project and thats just set context to module.
Spring is this loose coupled, not that loose coupled
You king of can use spring only for web module, but you will need to create wrapper components for datalib classes. And I don’t think it’s possible to use Spring based datalib in cli if cli is not Spring based. But I might be wrong.