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.
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.
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.