Architecting a Multi-Module Spring Boot Application Structure

Layered Module Architecture

The foundation relies on a hierarchical Maven aggregation strategy. A root Spring Boot aggregator orchestrates dependency inheritance, while distinct child modules operate as independent deployment units. A dedicated commons artifact consolidates reusable components, including domain models, persistence layers, utility functions, and framework configurations. All backend services inherit from this shared library. Separate modules handle RESTful controllers, request interceptors, and global exception handling. Another module hosts client-side static assets, encompassing stylesheets, scripts, markup templates, and media files.

Root Aggregator Setup

Eliminate the default source directories since the parent functions solely as a dependency repository. Integrate compilation aids and enforce consistent build parameters across all descendants.

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.boot.platform>2.2.13.RELEASE</spring.boot.platform>
</properties>

Child Module Provisioning

Instantiate four distinct artifacts tailored to specific operational scopes. Assign unique network ports to executable runtimes to prevent binding collisions during concurrent execution. The shared resource layer remains stateless and requires no server port allocation.

  • Administrative Console: 9999
  • Public API Endpoint: 8080
  • Client Frontend: 80

Runtime Bootstrap Configuration

Implement standard initialization routines within each executable module to trigger the application context.

@SpringBootApplication(scanBasePackages = {"com.app.admin.controller"})
public class AdminBootstrapper {
    public static void main(String[] args) {
        SpringApplication.run(AdminBootstrapper.class, args);
    }
}

@SpringBootApplication(scanBasePackages = {"com.app.api.handler"})
public class ApiBootstrapper {
    public static void main(String[] args) {
        SpringApplication.run(ApiBootstrapper.class, args);
    }
}

@SpringBootApplication(scanBasePackages = {"com.app.web.runner"})
public class ClientBootstrapper {
    public static void main(String[] args) {
        SpringApplication.run(ClientBootstrapper.class, args);
    }
}

Global Dependency Resolution

Leverage Maven's <dependencyManagement> block to centralize version control. Importing the Spring Boot Bill of Materials (BOM) automatically resolves compatible third-party releases. Internal module versions are explicitly declared here, allowing downstream artifacts to reference them without appending <version> tags.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.platform}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.app.internal</groupId>
            <artifactId>shared-commons</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</dependencyManagement>

When integrating the commons library into downstream services, declare only the group and artifact identifiers. The frontend client module typically omits this dependency unless bridging server-side rendering is required.

Core Library Inclutions

Consolidate foundational toolchains within the shared artifact to eliminate redundant declarations across sibling projects.

<dependencies>
    <!-- Embedded Servlet Container -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Relational Database Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.45</version>
    </dependency>

    <!-- Object-Relational Mapping Extension -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>

    <!-- Dynamic Mapper Generator -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.3.2</version>
    </dependency>

    <!-- Template Rendering Engine -->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.0</version>
    </dependency>

    <!-- Serialization Library -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.78</version>
    </dependency>
</dependencies>

Replicate the spring-boot-starter-web inclusion within the frontend artifact if an embedded Tomcat instance is required to serve static routes local. Execute a clean workspace purge (mvn clean) prior to recompilation to resolve cached artifact discrepancies.

Persistence Layer Configuration

Establish the target schema utilizing standard relational database administration tools.

Directly mapping database credentials poses security risks and creates environment isolation challenges. Enstead, externalize connection parameters into a dedicated environment file, such as db.properties, placed inside the commons resources directory. This prevents naming collisions when the commons JAR is packaged and injected into other modules.

db.connection.driver=com.mysql.cj.jdbc.Driver
db.connection.url=jdbc:mysql://localhost:3306/project_schema?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
db.connection.username=admin_user
db.connection.password=secure_password
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

The Spring container must explicitly register this file to parse key-value pairs correctly. Implement a configuration class annotated with @PropertySource to point toward the custom location, followed by explicit EnvironmentPostProcessor logic to bind values to Spring's property placeholders. Once validated, the multi-module topology is fully initialized and ready for feature implementation.

Tags: spring-boot Maven microservices java Architecture

Posted on Mon, 01 Jun 2026 17:32:44 +0000 by Yawa