Spring WebFlux Service Pattern & Dependency Injection
Dependency Injection (Constructor-Based)
Example
java
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}Guidelines
- Always prefer constructor injection for required dependencies.
- Use
@Autowiredon constructors only if multiple constructors exist. - Avoid field injection except in test classes.
Lombok Integration for Dependency Injection and Services
Lombok can reduce boilerplate in service classes by automatically generating constructors and other methods. Use Lombok's @RequiredArgsConstructor to enable constructor-based dependency injection without manually writing the constructor.
Example with Lombok
java
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
// ...
}- The
private finalfield(s) are injected via the generated constructor. - No need to manually write the constructor.
- Works seamlessly with Spring's dependency injection.
Guidelines
- Use
@RequiredArgsConstructorfor services with final dependencies. - Use
@AllArgsConstructorif you need all fields injected (not just final). - Avoid using Lombok for fields that should not be injected.
- Always annotate the class with
@Service(or@Component). - Lombok requires the Lombok plugin in your IDE and the dependency in your build file (Maven/Gradle).
Service Pattern
Example
java
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public Mono<UserDto> getUserById(String id) {
return userRepository.findById(id)
.map(this::mapToDto)
.switchIfEmpty(Mono.error(new ResourceNotFoundException("User not found")));
}
// ... other business logic using Mono/Flux ...
}Guidelines
- Annotate with
@Service. - Use constructor injection for dependencies.
- Keep business logic here, not in controllers or repositories.
- Return
Mono<T>orFlux<T>to controllers for all service methods. - Throw custom exceptions for error cases using
Mono.errororFlux.error. - Avoid blocking calls; use only reactive repositories and APIs.
- Map entities to DTOs before returning.