Spring Boot Annotations Guide
Essential Spring Boot annotations with code examples: stereotype annotations, dependency injection, configuration, request mapping, and validation.
1. Stereotype Annotations
// @RestController = @Controller + @ResponseBody
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
// Constructor injection (preferred over @Autowired field injection)
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public List<UserDto> getAll() {
return userService.findAll();
}
@GetMapping("/{id}")
public ResponseEntity<UserDto> getById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserDto create(@Valid @RequestBody CreateUserRequest req) {
return userService.create(req);
}
@PutMapping("/{id}")
public UserDto update(@PathVariable Long id, @Valid @RequestBody UpdateUserRequest req) {
return userService.update(id, req);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
userService.delete(id);
}
}
2. @Service & @Repository
@Service
@Transactional(readOnly = true)
public class UserService {
private final UserRepository repo;
private final PasswordEncoder encoder;
public UserService(UserRepository repo, PasswordEncoder encoder) {
this.repo = repo;
this.encoder = encoder;
}
public List<UserDto> findAll() {
return repo.findAll().stream().map(UserDto::from).toList();
}
@Transactional
public UserDto create(CreateUserRequest req) {
if (repo.existsByEmail(req.email())) {
throw new ConflictException("Email already in use");
}
User user = new User(req.name(), req.email(), encoder.encode(req.password()));
return UserDto.from(repo.save(user));
}
}
// @Repository adds exception translation (DataAccessException)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);
Optional<User> findByEmail(String email);
List<User> findByRoleAndIsActiveTrue(String role);
}
3. @Value & @ConfigurationProperties
// @Value โ inject single property
@Component
public class JwtConfig {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration:3600}") // default 3600
private long expiration;
@Value("${app.allowed-origins}")
private List<String> allowedOrigins;
}
// @ConfigurationProperties โ type-safe config binding (preferred)
@Configuration
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {
@NotBlank
private String name;
private Security security = new Security();
private Database database = new Database();
@Data
public static class Security {
private String jwtSecret;
private Duration jwtExpiration = Duration.ofHours(1);
private List<String> allowedOrigins = List.of();
}
@Data
public static class Database {
private int maxPoolSize = 10;
private Duration connectionTimeout = Duration.ofSeconds(30);
}
// getters/setters
}
4. @Component & @Bean
// @Component โ generic Spring-managed bean
@Component
public class SlugGenerator {
public String generate(String input) {
return input.toLowerCase().replaceAll("[^a-z0-9]+", "-");
}
}
// @Bean inside @Configuration โ explicit bean declaration
@Configuration
public class AppConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
@Bean
public ObjectMapper objectMapper() {
return JsonMapper.builder()
.addModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}
@Bean
@ConditionalOnProperty(name = "feature.cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users", "articles");
}
}
5. Validation Annotations
import jakarta.validation.constraints.*;
public record CreateUserRequest(
@NotBlank @Size(min = 1, max = 100)
String name,
@NotBlank @Email
String email,
@NotBlank @Size(min = 8, max = 128)
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$",
message = "Must contain upper, lower, and digit")
String password,
@Min(0) @Max(150)
Integer age,
@NotEmpty
List<@NotBlank String> roles
) {}
6. Annotations Quick Reference
| Annotation | Layer | Purpose |
|---|---|---|
| @SpringBootApplication | App | Main entry point |
| @RestController | Web | REST endpoint class |
| @RequestMapping | Web | URL prefix for class/method |
| @GetMapping/@PostMapping | Web | HTTP method mapping |
| @Service | Service | Business logic bean |
| @Repository | Data | DAO bean + exception translation |
| @Transactional | Data | Transaction boundary |
| @Autowired | Any | Dependency injection (avoid field) |
| @Value | Any | Inject property value |
| @ConfigurationProperties | Config | Type-safe config binding |
| @Profile | Any | Conditional by Spring profile |