Skip to content

A production-ready Spring Boot starter template implementing Hexagonal (Ports & Adapters) Architecture with clear domain boundaries, testable core, and modular design for scalable microservices.

Notifications You must be signed in to change notification settings

tranquocthong/java-hexagonal-template

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Hexagonal Architecture Template

A production-ready hexagonal architecture template for reactive Spring Boot applications using R2DBC.

πŸš€ Quick Start

# 1. Copy template
cp -r com/example/payments src/main/java/io/f8a/yourmodule

# 2. Update package names
find src/main/java/io/f8a/yourmodule -type f -name "*.java" \
  -exec sed -i '' 's/com.example.payments/io.f8a.yourmodule/g' {} +

# 3. Customize domain models and implement your use cases

πŸ“¦ Architecture Overview

com.example.payments/
β”œβ”€β”€ domain/                          # πŸ”΅ Pure Business Logic (No dependencies)
β”‚   β”œβ”€β”€ model/                       # Domain entities with business rules
β”‚   └── service/                     # Complex business logic
β”‚
β”œβ”€β”€ application/                     # 🟒 Use Cases & Orchestration
β”‚   β”œβ”€β”€ ports/in/                    # Input ports (what app does)
β”‚   β”œβ”€β”€ ports/out/                   # Output ports (what app needs)
β”‚   β”œβ”€β”€ handler/                     # Request handlers
β”‚   └── service/                     # Use case implementations
β”‚
β”œβ”€β”€ adapter/                         # 🟑 External World
β”‚   β”œβ”€β”€ in/                          # Inbound (web, kafka, jobs)
β”‚   β”‚   └── web/
β”‚   β”‚       β”œβ”€β”€ dto/                 # βœ… HTTP DTOs belong here
β”‚   β”‚       β”œβ”€β”€ mapper/              # βœ… HTTP mappers belong here
β”‚   β”‚       └── PaymentController.java
β”‚   └── out/                         # Outbound (db, clients, kafka)
β”‚       β”œβ”€β”€ db/
β”‚       β”‚   β”œβ”€β”€ entity/              # βœ… DB entities organized
β”‚       β”‚   β”œβ”€β”€ mapper/              # βœ… DB mappers organized
β”‚       β”‚   └── PaymentPersistenceAdapter.java
β”‚       └── restclient/
β”‚           β”œβ”€β”€ dto/                 # βœ… External service DTOs
β”‚           └── mapper/              # βœ… External service mappers
β”‚
└── infrastructure/                  # 🟣 Configuration ONLY
    β”œβ”€β”€ config/                      # Core application configuration
    β”œβ”€β”€ persistence/                 # Database & transaction configuration
    β”œβ”€β”€ messaging/                   # Kafka & event streaming
    β”œβ”€β”€ cache/                       # Redis & caching policies
    β”œβ”€β”€ http/                        # WebClient & HTTP configuration
    β”œβ”€β”€ security/                    # Security & authentication
    β”œβ”€β”€ observability/              # Monitoring & tracing
    β”œβ”€β”€ resilience/                 # Fault tolerance patterns
    β”œβ”€β”€ errorhandling/              # Global error handling
    └── profiles/                   # Environment configurations

🎯 Key Principles

Dependency Rule

Adapters β†’ Application β†’ Domain

Dependencies always flow inward. Domain has no dependencies.

Layer Responsibilities

  • Domain: Pure business logic, entities, domain services
  • Application: Use cases, orchestration, defines ports
  • Adapters: External world interaction, implements ports
  • Infrastructure: Configuration, bean wiring, migrations

Correct Structure (Fixed)

βœ… DTOs and Mappers belong to Adapters (not Infrastructure)

  • HTTP DTOs β†’ adapter/in/web/dto/
  • DB entities β†’ adapter/out/db/entity/
  • External DTOs β†’ adapter/out/restclient/dto/
  • Infrastructure β†’ Configuration ONLY

πŸ”„ Request Flow

HTTP POST /api/v1/payments
    ↓
PaymentController (adapter/in/web)
    ↓
CreatePaymentRequestHandler (application/handler)
    ↓
CreatePaymentService (application/service)
    β”œβ†’ PaymentDomainService (domain/service) - Validation
    β”œβ†’ SavePaymentPort β†’ PaymentPersistenceAdapter (adapter/out/db)
    β””β†’ PublishEventPort β†’ PaymentEventProducer (adapter/out/kafka)

πŸ› οΈ Technology Stack

  • Java 21 + Spring Boot 3.5.3 (Reactive WebFlux)
  • R2DBC (Reactive database) + PostgreSQL
  • Project Reactor (Reactive programming)
  • MapStruct (Object mapping) + Lombok
  • Kafka (Event streaming) + Redis (Caching)
  • Flyway (Database migrations)

πŸ“‹ Implementation Steps

1. Define Domain (Pure Business Logic)

// domain/model/Payment.java
@Data @Builder
public class Payment {
  private String id;
  private BigDecimal amount;
  
  // Business rules as methods
  public boolean canBeCancelled() {
    return status == PaymentStatus.PENDING;
  }
}

// domain/service/PaymentDomainService.java
public class PaymentDomainService {
  public ValidationResult validate(Payment payment) {
    // Pure business validation logic
  }
}

2. Define Ports (Interfaces)

// Input ports (what app does)
public interface CreatePaymentUseCase {
  Mono<Payment> createPayment(CreatePaymentCommand command);
}

// Output ports (what app needs)
public interface SavePaymentPort {
  Mono<Payment> save(Payment payment);
}

3. Implement Services (Orchestration)

@Service
@RequiredArgsConstructor
public class CreatePaymentService implements CreatePaymentUseCase {
  private final PaymentDomainService domainService;
  private final SavePaymentPort savePaymentPort;
  
  public Mono<Payment> createPayment(CreatePaymentCommand command) {
    return buildPayment(command)
      .flatMap(domainService::validate)
      .flatMap(savePaymentPort::save);
  }
}

4. Create Adapters

// Inbound: REST Controller
@RestController
public class PaymentController {
  @PostMapping("/payments")
  public Mono<ApiResponse<PaymentResponse>> create(@RequestBody CreatePaymentRequest req) {
    return handler.handle(req).map(ApiResponse::success);
  }
}

// Outbound: Database Adapter
@Component
public class PaymentPersistenceAdapter implements SavePaymentPort {
  public Mono<Payment> save(Payment payment) {
    return repository.save(toEntity(payment)).map(this::toDomain);
  }
}

πŸ§ͺ Testing Strategy

// Domain (Pure unit tests)
PaymentDomainService service = new PaymentDomainService();
assertThat(service.validate(payment).isValid()).isTrue();

// Application (Mock ports)
@Mock SavePaymentPort savePort;
StepVerifier.create(service.createPayment(command))
  .assertNext(payment -> assertThat(payment).isNotNull())
  .verifyComplete();

// E2E (Full stack)
webClient.post().uri("/api/v1/payments")
  .exchange().expectStatus().isOk();

πŸ“š Documentation Structure

File Purpose Priority
README.md Overview & quick start πŸ”΄ Essential
ARCHITECTURE.md Detailed concepts & patterns 🟑 Important
IMPLEMENTATION.md Step-by-step guide 🟑 Important

πŸ—οΈ New Infrastructure Organization

The infrastructure layer has been completely refactored into specialized configuration categories:

Configuration Categories

  • config/ - Core application configuration (ObjectMapper, Validation, Reactor)
  • persistence/ - Database, transactions, migrations, ID generation
  • messaging/ - Kafka configuration, topics, serialization
  • cache/ - Redis configuration and caching policies
  • http/ - WebClient, observability, CORS, rate limiting
  • security/ - Authentication, authorization, data masking
  • observability/ - Metrics, tracing, logging configuration
  • resilience/ - Circuit breakers, retry policies, bulkheads
  • errorhandling/ - Global exception handling and error responses
  • profiles/ - Environment-specific configurations

Key Features

  • Production Ready: Comprehensive observability, security, and resilience
  • Environment Management: Separate configs for dev/staging/prod
  • Fault Tolerance: Circuit breakers, retries, timeouts, bulkheads
  • Security: JWT authentication, data masking, CORS protection
  • Monitoring: Metrics, distributed tracing, structured logging
  • Caching: Redis integration with configurable policies
  • Error Handling: RFC 7807 Problem Details with correlation IDs

✨ Benefits

  • Testability: Test each layer independently
  • Flexibility: Swap implementations easily (DB, API, messaging)
  • Maintainability: Clear separation of concerns
  • Scalability: Reactive programming for high throughput
  • Production Ready: Enterprise-grade configuration and monitoring
  • Organized: Specialized configuration categories for better maintenance

πŸŽ“ Next Steps

  1. Read this README for overview
  2. Study code examples in template
  3. Follow implementation steps
  4. Customize for your domain
  5. Write tests and deploy

Template Status: βœ… Production Ready
Architecture: Hexagonal (Ports & Adapters)
Pattern: Reactive with R2DBC
Java Version: 21 | Spring Boot: 3.5.3

About

A production-ready Spring Boot starter template implementing Hexagonal (Ports & Adapters) Architecture with clear domain boundaries, testable core, and modular design for scalable microservices.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages