Skip to content
Model centric tools for Spring development Community portal
Skyway PerspectivesModel driven delivery

Recipes

Recipe: Wiring the Service Layer

The service recipe is where transactions, business rules and repository calls meet. This page explains the generated interface, its implementation and the wiring options.

Four stacked application layers for Spring MVC and Spring Web Flow
Figure 2.8. The service layer sits between controllers and repositories.

A service recipe produces two types for each model service: an interface and an implementation. The interface describes the operations that controllers may call. The implementation holds the transaction boundary and the calls to repositories. Keeping the pair separate makes it simple to replace an implementation in a test.

Generated operations

  • Find operations. Read a single record by key, or list records with an optional filter.
  • Save operations. Create or update a record and return the managed result.
  • Remove operations. Delete a record by key and report whether a row was affected.
  • Custom operations. Operations added to the model type and marked for generation.

Transaction boundaries

The implementation is annotated at class level with a read only transaction hint, and write operations override it. Start with a single transaction per public write operation. If a use case needs to span several operations, add a dedicated service method rather than calling one service from another. The wider transaction belongs in the layer that owns the use case.

@Service
@Transactional(readOnly = true)
public class CustomerServiceImpl implements CustomerService {

    private final CustomerRepository repository;

    public CustomerServiceImpl(CustomerRepository repository) {
        this.repository = repository;
    }

    @Transactional
    public Customer save(Customer customer) {
        return repository.save(customer);
    }
}

Wiring the repository

The service holds a reference to one repository per model type. The generator writes constructor injection by default. When a project uses XML configuration, the recipe also writes the bean entries. Choose one wiring style per project and keep it consistent, because mixing styles makes the context hard to read.

Testing note. Because the service depends on an interface, a unit test can pass a small stub repository. The generated test starter already does this for the save and find operations.

If a service needs a second data source, model the repository reference explicitly and adjust the recipe to add a qualifier. The generator will carry the qualifier into the constructor parameter.