Controllers, Beans & Configuration
REST Controllers & Dependency Injection
@SpringBootApplication // @Configuration + @EnableAutoConfiguration + @ComponentScan
public class MyAppApplication {
public static void main(String[] args) {
SpringApplication.run(MyAppApplication.class, args);
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
// Constructor injection — preferred over field injection: dependencies
// are explicit, fields can be final, and a plain unit test can new()
// this class with mocks with no Spring context needed at all
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public UserDto getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public UserDto createUser(@Valid @RequestBody CreateUserRequest request) {
return userService.create(request);
}
}Beans, Services & Repositories
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional // rolls back automatically on unchecked exceptions;
// checked exceptions need explicit rollbackFor to trigger rollback
public UserDto create(CreateUserRequest request) {
User user = new User(request.email(), request.name());
return toDto(userRepository.save(user));
}
}
// Zero implementation needed — Spring generates it via a dynamic proxy
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}Configuration
# application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
profiles:
active: dev
app:
api-key: ${API_KEY}
rate-limit:
requests-per-minute: 100// Type-safe group binding — preferred over scattered @Value fields,
// which silently resolve to null on a typo'd property key with no error
@ConfigurationProperties(prefix = "app.rate-limit")
public record RateLimitProperties(int requestsPerMinute) {}
@Value("${app.api-key}")
private String apiKey; // fine for a single isolated valueKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free