Hexagonal architecture in java

1. Overview

In this article, we’ll implement hexagonal architecture using a Book application. We’ll create a simple application that will allow us to save books with a small description of the book along with its name and author.

2. Hexagonal Architecture

Hexagonal architecture is a model or pattern for application design. The main goal of this architecture is to separate the core business logic from the other concerns. It divides the application into two parts -inner and outer. The inner part contains the core logic. The outer part can have UI, database, messaging connectors. Both parts communicate with each other through a mechanism of port and adapters. Port acts as a gateway for communication and an adapter is an implementation of the port.

Ports are interfaces that allow inbound and outbound flows. Therefore the core part of the application communicates with the outside part using the dedicated port.

  • Inbound: Exposes the core application to the outside. It is an interface that can be called from outside components.
  • Outbound: Allows outside functionality in the core application. It enables the use case of the core application to communicate with outside such as a database.

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

  • Primary: They drive the application by invoking the corresponding use case of the core application using the inbound ports.
  • Secondary: These are the implementation of the outbound ports.

3. Example

Let’s understand this architecture with an example. We’ll be designing a Book application. Features of our application include creating a new book, searching books by name, and listing all books. We’ll divide our application into three layers.

  • Domain: Core business logic layer
  • Application: Acts as a mediator between domain layer and infrastructure layer.
  • Infrastructure/Framework: Has all implementation details and how the domain layer will interact with the external world.

4. Domain Layer

Let’s first create a Book object:

public class Book {
private long id;
private String name;
private String author;
private String description;
//constructor, getters. setters
}

Now define an interface through which the core application will do communication. It exposes the core application to the outside world:

public interface BookService{
public void createBook(Book book);
public Book getBook(String name);
public List<Book> listBook();
}

Create one more interface to create or access the outside world:

public interface BookRepository extends JpaRepository<Book,Long> {
Optional<Book> findOneByName(String name);
}

5. Application Layer

Let’s create a REST controller:

public class BookController {

@Autowired
private BookService bookService;

@PostMapping(value = "book", produces = MediaType.APPLICATION_JSON_VALUE)
public void createBook(@RequestBody Book book) {
bookService.createBook(book);
}

@GetMapping(value = "book/{name}", produces = MediaType.APPLICATION_JSON_VALUE)
public Book getBook(@PathVariable String name)
{
return bookService.getBook(name);
}

@GetMapping(value = "book-list", produces = MediaType.APPLICATION_JSON_VALUE)
public List<Book> listBook()
{
return bookService.listBook();
}
}

6. Infrastructure Layer

Finally, let’s create an implementation class that will be responsible for communication between core application to the data source:

public class BookServiceImpl implements BookService{

@Autowired
BookRepository bookRepository;

@Override
public void createBook(Book book) {
bookRepository.save(book);
}

@Override
public Book getBook(String name) {
Book book= bookRepository.findOneByName(name).orElseThrow(()-> new EntityNotFoundException("No book found with this name"));
return book;
}

@Override
public List<Book> listBook() {
return bookRepository.findAll();
}
}

7. Conclusion

In this article, we’ve learned how we can simplify the architecture of an application by separating our logic into different layers. The core business logic is isolated from the external dependencies. The ports give us the flexibility in connecting to new adapters.

All of these code examples are available on GitHub.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store