Hexagonal Architecture in Java

A practical example of Hexagonal Architecture in Java

Anirban Chatterjee
Javarevisited
5 min readMay 23, 2020

--

1. Overview

In this tutorial, we’ll take a look into the hexagonal architecture in Java. To illustrate this further, we’ll create a Spring Boot application.

2. Hexagonal Architecture

The hexagonal architecture describes a pattern for designing software applications around the domain logic. The hexagon describes the core of the application consisting of the domain object and the use cases of the application.

The edges of the hexagon provide the inbound and outbound ports to the outside parts of the hexagon such as web interface, databases, etc. So, in this kind of software architecture, all the dependencies between the components point towards the domain object.

Therefore, the communication between the core application and the outside part is only possible using ports and adapters.

In the following sections, we can have a deep dive into the different layers of the hexagonal architecture.

3. Domain Object

The domain object is the core part of the application. It can have both state and behavior. However, it doesn’t have any outward dependency. So any change in the other layers has no impact on the domain object.

The domain object changes only if there is a change in the business requirement. Hence, this is an example of the Single Responsibility Principle among the SOLID principles of software design.

First, let’s create a domain object Product which forms the core of the application. It contains product-related information and business validations:

4. Ports

The ports are interfaces that allow inbound and outbound flow. Therefore, the core part of the application communicates with the outside part using the dedicated ports.

4.1. Inbound Port

The inbound port exposes the core application to the outside. It is an interface that can be called by the outside components. These outside components calling an inbound port are called primary or input adapters.

Let’s define an interfaceProductService which is the inbound port:

4.2. Outbound Port

The outbound port allows outside functionality to the core application. It is an interface that enables the use case of the core application to communicate with the outside such as database access. Hence, the outbound port is implemented by the outside components which are called secondary or output adapters.

5. Adapters

The adapters are the outside part of the hexagonal architecture. So, they interact with the core application only by using the inbound and outbound ports.

5.1. Primary Adapters

The Primary adapters are also known as input or driving adapters. Therefore, they drive the application by invoking the corresponding use case of the core application using the inbound ports. For example, primary adapters are REST APIs or web interfaces.

Let’s define a ProductController class as our primary adapter. In particular, it’s a REST controller that provides endpoints for creating and accessing products. Subsequently, it uses the inbound port service to interact with the core application:

5.2. Secondary Adapters

The Secondary adapters are also known as output or driven adapters. These are implementations of the outbound port interface. The use case of the core application invokes the secondary adapters using the output port. For instance, secondary adapters are connections to the database and external API calls.

Let’s define a classProductRepositoryImplementation as our secondary adapter. In particular, this class implements the outbound port interface ProductRepository and allows the core application to access the database:

The adapters provide flexibility to the application without influencing the core application logic. If the application can be used by a new client in addition to the existing one, we can add the new client to the inbound port. In addition, if the application requires a different database, we can add a new secondary adapter implementing the same outbound port.

6. Use cases of the core application

The use cases of the core application are the inside part of the hexagonal architecture. They are specific use case implementations of the inbound port. Hence, it contains all the use case-specific business rule validations and logic. The uses case has no outside dependency similar to the domain objects.

Let’s define a classProductServiceImplementation which provides the specific use case implementation:

7. Conclusion

The hexagonal architecture offers several benefits compared to a layered architecture:

  • It simplifies the architecture design by separating the inside and outside parts of the application
  • The core business logic is isolated from any external dependencies which help to achieve a high degree of decoupling
  • The ports allow flexibility in connecting to new adapters in the form of new web clients or databases

The hexagonal architecture might be an overhead for designing simple CRUD applications. However, this architecture is useful when we are designing a domain-driven application.

The code for these examples is available over on Github.

Originally published on Anirban’s Tech Blog

--

--

Anirban Chatterjee
Javarevisited

Software Engineer | Blogger | Traveler | Football fan | Amateur Photographer