简体   繁体   中英

DDD Java with Spring - Repository returning Mono/Flux

I'm wondering about one issue encountered when implementing reactive Mongo repository in a DDD project which I implement using Java and Spring Boot. Suppose we have such package structure:

/app 
  |
  |------/application
  |        | 
  |        |------/order
  |                 |
  |                 |------OrderApplicationService.java
  |
  |------/domain
  |        |
  |        |------/order
  |                 |
  |                 |------Order.java
  |                 |------OrderRepository.java 
  |
  |------/infrastructure
           |
           |------/mongo
                    |
                    |------MongoOrderRepository.java

I my OrderRepository.java I want to have a method to save my Order:

public interface OrderRepository {

    Order save(Order order);
}

And use it in my application service:

@Service
public class OrderApplicationService {

    private final OrderRepository orderRepository;

    public OrderApplicationService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void createOrder() {
        //Dumb order creation
        Order createdOrder = clientRepository.save(new Order());
    }
}

Next I want to write MongoOrderRepository which implements OrderRepository. Suppose I will use ReactiveMongoTemplate. The problem is that all its methods return Flux or Mono, so I can't implement my method from OrderRepository interface.

Possible solutions I see are:

  1. Make 'save' method in OrderRepository return an Order wrapped by Mono. This approach will polute the domain layer with Reactor specific types and break the rule saying that domain layer should be framework code free.
  2. Develop some sort of wrapping layer, but this will produce some boilerplate code.
  3. Move OrderService.java to infrastructure layer, but this also breaks some basic DDD concepts.

Does someone see any better solutions?

The repository should be agnostic of framework code, that's true and that's a good practice, but you need to be pragmatic as well, I had repository where I used java lambda, which are language level framework one could argue.

What is the benefit of using Flux or Mono, and what is the benefit of advertising them as part of the interface ? If there is none, you can then keep the implementation detail into the repository implementation and keep the interface free of reactive objects.

However, if this needs to span through the application layer to the port adapters, then I don't see any issues putting them in the interface definition of your repository.

That being said, you might want to check another approach, with CQRS and Hexagonal Architecture, you can have best of both worlds:

  • Having a clean repository interface for the command (Update and Create part)
  • Using a Query Service (plain POJO if you are in java, defined in your application package) returning a Mono or Flux for the Query (Read part)

    OrderApplicationService.java (here go the Create Update Delete via commands) OrderQueryService.java (here go the Read part)

Your application service contains a reference to your OrderRepository, the query service does not use the repository as it query more directly the db, via ReactiveMongoTemplate for instance.

In my Query services I used plain JDBC Templates for instance while using Hibernate in the repository implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM