Skip to content

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 @Autowired on 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 final field(s) are injected via the generated constructor.
  • No need to manually write the constructor.
  • Works seamlessly with Spring's dependency injection.

Guidelines

  • Use @RequiredArgsConstructor for services with final dependencies.
  • Use @AllArgsConstructor if 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> or Flux<T> to controllers for all service methods.
  • Throw custom exceptions for error cases using Mono.error or Flux.error.
  • Avoid blocking calls; use only reactive repositories and APIs.
  • Map entities to DTOs before returning.

References

Copyright © MSG Systems Romania AI Labs