SpringBoot

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>

file: rootProject/pom.xml

<project ..>
  ...
  <!-- modules -->
  <modules>
    <module>web</module>
    <module>cli</module>
    <module>datalib</module>
  </modules>

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.