Spring Boot
01 / 02

Controllers, Beans & Configuration

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 value

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free