Multi-Module Project With Spring Boot

In this article, we’ll see how to create a multi-module project with Spring Boot. We will create 2 projects for this multi module application with a parent project works as a container.

Introduction

Before we get into more details, let’s try to answer a simple question “What are the benefits of multi-module projects in Spring Boot“?. Here are some benefits of multi-module project with Spring Boot:

  • Provide the ability to build all modules with a single command. Run the build command from parent module.
  • Build system take care of the build order.
  • Make it easy and flexible to deploy the application.
  • You can re-use the code from the modules across different projects.

1. Spring Boot Parent Module

To start with our spring boot multi-module project, the first step is to create a simple parent project. This parent module contains a pom.xml file and our pom.xml will have the following details:

  1. List of all the modules (actual projects).
  2. List of common dependencies across all modules (we need not duplicate it on all modules).
  3. Common configuration for all modules (e.g. java version etc.)

As part of the Spring Boot application, we will also add the spring-boot-starter-parent dependency. It is the parent POM providing dependency and plugin management for Spring Boot-based applications. This step is optional but highly recommended for Spring Boot application. To create the parent project, we have the following 2 options:

  1. Create pom.xml manually.
  2. Use maven quick-start archetype

Let’s use the 2nd option to generate the parent project.

mvn archetype:generate -DgroupId=com.javadevjournal
        -DartifactId=spring-boot-multi-module-project
        -DarchetypeArtifactId=maven-archetype-quickstart
        -DinteractiveMode=false

Once we run above command, Maven will create a structure for us along with the pom.xml file. Change the packaging type as pom for this parent module. This is how the final pom.xml look like.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.javadevjournal</groupId>
   <artifactId>spring-boot-multi-module-project</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>pom</packaging>
   <name>spring-boot-multi-module-project</name>
   <url>https://javadevjournal.com</url>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.2.4.RELEASE</version>
   </parent>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
      <java-version>1.8</java-version>
   </properties>
   <modules>
      <module>jdj-core</module>
      <module>jdj-web</module>
   </modules>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
      </dependency>
   </dependencies>
</project>

In our pom.xml file, we are defining spring-boot-starter as the global dependency (as we need it in all module). We’ll create two directories inside our project. These 2 directories represents the sub-modules defined in the parent pom.xml file.

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

2. Child Modules

Let’s create our child modules. We can define any child module based on our requirements. Define child modules which are interdependent (like core module and web module dependent on the core module) or define independent module. There are no limitations or restrictions on the module structure and it’s completely based on individual project requirements. We are defining the following structure.

  1. Module with a jar packaging.
  2. a web module dependent upon our core module.

3. Sub-module – Core

Let’s create our core module. We will define a simple customer service in our core module. For this article, let’s create our core module using Spring initializer but you can create it using your IDE or through maven.

Multi-Module Project With Spring Boot

I am not selecting any dependency in the module but you can add as per your requirement (Add module specific dependency in this section, for the application wide dependencies, use the parent module pom). Click on the “Generate button” to download the project to your local machine. One of the best benefit of using Spring Boot based multi-module project is the ability to define the global dependencies at one place and let the child module re-use these configurations without duplicating it.

This is how our jdj-core pom.xml look like:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.javadevjournal</groupId>
      <artifactId>spring-boot-multi-module-project</artifactId>
      <version>0.0.1-SNAPSHOT</version>
   </parent>
   <groupId>com.javadevjournal</groupId>
   <artifactId>jdj-core</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>jdj-core</name>
   <description>Core module for our multi module Spring Boot application</description>
</project>

The interesting part of this pom.xml is the <parent> tag. This tag allows maven reads the parent POM from your local repository (or proxies like nexus) and creates an ‘effective POM’ by merging the information from parent and module POM.

<parent>
   <groupId>org.javadevjournal</groupId>
   <artifactId>spring-boot-multi-module-project&lt;/artifactId>
   <version>0.0.1-SNAPSHOT</version>
</parent>

3.1. Customer Service 

We are defining a simple CustomerService class. This service class will return the customer information based on the customer ID. It’s a simple class but shows how these different modules work together in the maven multi-module projects.

package com.javadevjournal.service.customer;

import com.javadevjournal.data.customer.Customer;
import org.springframework.stereotype.Service;

@Service("customerService")
public class DefaultCustomerService implements CustomerService {

    @Override
    public Customer getCustomerById(String id) {
        return new Customer("Test", "Customer", id, "[email protected]");
    }
}

4. Sub-module – Web

Next, we have the web module. Our web module also has a dependency on the core module (for the customer service). We will use Spring Boot to create the web module. We can either use the IDE or spring Initializr to create web module.

This is how the pom.xml look like:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.javadevjournal</groupId>
      <artifactId>spring-boot-multi-module-project</artifactId>
      <version>0.0.1-SNAPSHOT</version>
   </parent>
   <groupId>com.javadevjournal</groupId>
   <artifactId>jdj-web</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>jdj-web</name>
   <description>Web module for our multi module Spring Boot application</description>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>com.javadevjournal</groupId>
         <artifactId>jdj-core</artifactId>
         <version>0.0.1-SNAPSHOT</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
      <finalName>javadev-web</finalName>
   </build>
</project>

Let’s look at some important points in our web module:

  1. Similar to the core module, we are taking advantage of the Spring Boot dependency management with help of <parent> tag.
  2. We are including the jdj-core jar and Spring Boot web module as additional dependencies.
<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
      <groupId>com.javadevjournal</groupId>
      <artifactId>jdj-core</artifactId>
      <version>0.0.1-SNAPSHOT</version>
   </dependency>
</dependencies>

4.1. Controller

To test our application and see how the multi-module application is working, let’s create a simple customer controller in the web module with the following feature.

  1. Customer controller will use the customer service defined in the core module.
  2. customer service returns customer data based on the ID.

This is how the CustomerController looks like:

@RestController
@RequestMapping("/customers")
public class CustomerController {

    @Resource(name = "customerService")
    CustomerService customerService;

    @GetMapping("/customer/{id}")
    public Customer getCustomer(@PathVariable String id) {
        return customerService.getCustomerById(id);
    }
}

5. Build and Run application

For the preference purpose, This is how our multi module application looks in the Java editor:

Multi-Module Project With Spring Boot -intellij

To build our application, go to the parent module folder and run the mvn clean install command. Maven will start building all the modules based on the configuration in our parent pom. 

$ mvn clean install
INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] spring-boot-multi-module-project                                   [pom]
[INFO] jdj-core                                                           [jar]
[INFO] jdj-web                                                            [jar]
[INFO] 
[INFO] --------< org.javadevjournal:spring-boot-multi-module-project >---------
[INFO] Building spring-boot-multi-module-project 0.0.1-SNAPSHOT           [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-boot-multi-module-project ---
[INFO] 
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ spring-boot-multi-module-project ---
[INFO] Installing /Users/Javadevjournal/javadevjournal-git/Spring-Boot/spring-boot-multi-module-project/pom.xml to /Users/.m2/repository/org/javadevjournal/spring-boot-multi-module-project/0.0.1-SNAPSHOT/spring-boot-multi-module-project-0.0.1-SNAPSHOT.pom
[INFO] 
[INFO] --------------------< com.javadevjournal:jdj-core >---------------------
[INFO] Building jdj-core 0.0.1-SNAPSHOT                                   [2/3]
[INFO] --------------------------------[ jar ]---------------------------------

............

[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ jdj-web ---
[INFO] Building jar: /Users/Javadevjournal/javadevjournal-git/Spring-Boot/spring-boot-multi-module-project/jdj-web/target/javadev-web.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.2.4.RELEASE:repackage (repackage) @ jdj-web ---
[INFO] Replacing main artifact with repackaged archive
[INFO] 
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ jdj-web ---
[INFO] Installing /Users/Javadevjournal/javadevjournal-git/Spring-Boot/spring-boot-multi-module-project/jdj-web/target/javadev-web.jar to /Users/.m2/repository/com/javadevjournal/jdj-web/0.0.1-SNAPSHOT/jdj-web-0.0.1-SNAPSHOT.jar
[INFO] Installing /Users/Javadevjournal/javadevjournal-git/Spring-Boot/spring-boot-multi-module-project/jdj-web/pom.xml to /Users/.m2/repository/com/javadevjournal/jdj-web/0.0.1-SNAPSHOT/jdj-web-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for spring-boot-multi-module-project 0.0.1-SNAPSHOT:
[INFO] 
[INFO] spring-boot-multi-module-project ................... SUCCESS [  1.476 s]
[INFO] jdj-core ........................................... SUCCESS [  3.720 s]
[INFO] jdj-web ............................................ SUCCESS [ 12.325 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  19.005 s
[INFO] Finished at: 2020-02-01T19:43:56-08:00
[INFO] ------------------------------------------------------------------------

As you must have noticed, when build started, Maven is displaying the build order (what we defined in the parent pom.xml file). To run our application, we can use the following command from the parent module by passing our application name.

mvn spring-boot:run -pl jdj-web

Or we can go to the specific module and run the above command without -pl.

5.1. Testing Application.

Once we start our application, it’s time to test our application, open the http://localhost:8080/customers/customer/1, on hitting the URL:

  1. Our CustomerController will be triggered.
  2. The custom controller will call the customer service defined in the jdj-core module.
output

Summary

In this article, we saw how to create a multi-module project with Spring Boot. We also saw the benefits and flexibilities of using the multi-module maven projects with your spring boot application. The source code for this application is available on the GitHub.