How to Build a Scalable Java Backend with a Modular Architecture
This guide outlines a flexible, modular Java backend architecture designed to improve delivery efficiency and reduce coupling, detailing the purpose, scope, project structure, module classifications, dependency rules, package management, and build configuration for architects and backend engineers.
Overview
Purpose : Define a flexible, reusable engineering code example that matches the system’s external output characteristics, thereby boosting overall delivery efficiency and minimizing quality issues caused by code coupling.
Applicable audience : System architects and backend Java engineers.
Project Overview
System Partition
The subsystem is split into two Maven projects:
dms-base (xxx-base) : Holds common foundation classes, basic business capabilities, and the first‑level abilities.
dms-core (xxx-core) : Contains second‑level capabilities, solution implementations, and extension points.
Module Classification
dms-base modules :
Public base classes and tools ( common)
System components ( component) – includes component-interface for business component interfaces and component-sdk for reusable business or technical components.
Adapter interface ( adapter-interface)
External interface ( core-facade)
dms-core modules :
Business entry orchestration ( core-orchestration)
Adapter implementation ( adapter) – infrastructure adapters ( adapter-infrastructure) and tenant‑specific adapters ( adapter-xxx)
Plugin modules ( plugin-xxx) for tenant plugins
Build launcher ( launcher, e.g., dms-core-launcher)
Dependency Principles
Rule 1 : Unstable modules may depend on stable modules, but stable modules must not depend on unstable ones.
Rule 2 : Detailed module‑level dependencies:
Core launcher aggregates all system modules.
Entry orchestration depends on the external interface module ( core-facade).
External interface, adapter interface, and component interface all depend only on the common base module ( common-entity).
Tenant adapter modules depend on adapter-interface and may optionally use common-entity and common-tool.
Tenant plugin modules depend on component-interface and adapter-interface, with optional common base usage.
Component modules (business component, basic component, SDK component) follow similar rules, with SDK components being completely independent of component-interface.
Module Details
Common Base Modules
Public base classes store request/response wrappers, enums, constants, and annotations that are used across the entire system. They are isolated to avoid pulling third‑party libraries into modules that only need the base definitions.
Public tools module provides global utilities such as user context objects, event publishers, and generic helper classes.
Component Modules
Basic components reside under component-sdk and are intended for reuse by other systems. They expose their own interfaces and entities, keeping them independent of the business component interface module.
Business function interface components define contracts for business functionality; they do not contain implementation code.
Business function components implement the contracts defined in the interface components and may also expose additional services. Service packages are organized by business domain (e.g., service.cases, service.commission).
Package Management Module
The base Maven project manages the version of the entire system. The core project inherits the version from base via its parent POM. All other modules reference the constant dms.version and must not define their own versions.
Version management is enforced with a Maven plugin (illustrated in the accompanying diagram).
Adapter Modules
Adapter interface module stores external dependency contracts, separating business service dependencies ( biz) from infrastructure dependencies ( infras) such as MQ, KMS, workflow, email, etc.
Infrastructure adapter modules implement these contracts for shared infrastructure services. They are tenant‑agnostic and avoid code duplication across tenant adapters.
Tenant adapter modules are created per tenant when a tenant‑specific adaptation scenario exists.
Business Entry Orchestration Module
Each subsystem has a single entry orchestration module that coordinates business flows. It depends on the external interface module ( core-facade), the business component interface module ( component‑interface), and optionally the adapter interface module.
Entry points include:
Controller – handles front‑end requests.
Facade – exposes services to external callers.
Job – batch processing tasks.
Message – message‑driven entry points.
All inbound classes should contain only service composition logic; actual business logic resides in the service layer. Input validation uses hibernate‑validator annotations, and RPC interfaces (e.g., Dubbo) require parameter validation configuration.
Build Launcher Module
The launcher aggregates all modules and contains startup configuration classes and common interceptors.
Tenant Plugin Module
Tenant plugins are organized per tenant. They listen to events published by core business modules (using Spring’s event mechanism) to achieve decoupling. For tenant‑specific logic that replaces core behavior, the SPI mechanism is used, with implementation classes declared in META‑INF/services files.
Images
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect-Kip
Daily architecture work and learning summaries. Not seeking lengthy articles—only real practical experience.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
