| name | springboot-patterns |
| description | Use when building Spring Boot services, configuring profiles, implementing caching/async, setting up Actuator/Micrometer, or creating REST clients. Do NOT use for JPA (use jpa-patterns), API design (use api-design), security (use springboot-security), testing (use springboot-tdd), or Kotlin (use kotlin-patterns). |
| paths | **/*.java, **/build.gradle*, **/pom.xml, **/application*.yml, **/application*.properties |
Spring Boot Core Patterns
Spring Boot 3.x/4.x ํต์ฌ ํจํด. JPA, API ์ค๊ณ, ๋ณด์, ํ
์คํธ๋ ์ ์ฉ ์คํฌ ์ฐธ์กฐ.
Quick Start
When to Activate
- Spring Boot ์๋น์ค ๊ตฌ์ถ ๋ฐ ๊ตฌ์กฐ ์ค๊ณ
- @ConfigurationProperties, Profile ๊ด๋ฆฌ
- @ControllerAdvice ์์ธ ์ฒ๋ฆฌ, Bean Validation
- @Cacheable, @Async, @EventListener ๊ตฌํ
- Actuator, Micrometer ๋ชจ๋ํฐ๋ง ์ค์
- RestClient, HTTP Interface (Spring Boot 3.2+) ์ฌ์ฉ
CRITICAL Rules
- ALWAYS constructor injection โ field injection ๊ธ์ง (ํ
์คํธ ๋ถ๊ฐ, ์์กด์ฑ ์จ๊น)
- ALWAYS
spring.mvc.problemdetails.enabled=true โ RFC 7807 ํ์ค ์๋ฌ ์๋ต
- NEVER return entity directly from controller โ DTO ๋ถ๋ฆฌ ํ์
- ALWAYS externalize secrets โ
${ENV_VAR} ๋๋ Vault, ์ ๋ ํ๋์ฝ๋ฉ ๊ธ์ง
- PREFER record for DTOs and @ConfigurationProperties
- ALWAYS graceful shutdown โ
server.shutdown=graceful
- NEVER catch generic Exception silently โ ๋ก๊ทธ + ์ ์ ํ HTTP ์ํ ๋ฐํ
- ALWAYS
spring.main.keep-alive=true when virtual threads enabled โ daemon thread๋ก JVM ์กฐ๊ธฐ ์ข
๋ฃ ๋ฐฉ์ง
Project Structure
src/main/java/com/example/
โโโ config/ # @Configuration, @ConfigurationProperties
โโโ controller/ # @RestController (thin, delegation only)
โโโ service/ # @Service (business logic, transactions)
โโโ repository/ # Spring Data interfaces
โโโ domain/ # Entity, VO, enums
โโโ dto/ # Request/Response records
โโโ exception/ # Custom exceptions + @ControllerAdvice
โโโ filter/ # OncePerRequestFilter
โโโ event/ # ApplicationEvent + @EventListener
Rules:
- Controller๋ ์๊ฒ โ ๊ฒ์ฆ + ์์ + ์๋ต ๋ณํ๋ง
- Service์ ๋น์ฆ๋์ค ๋ก์ง ์ง์ค
- Entity โ DTO ๋ณํ์ DTO์
static from() ํฉํ ๋ฆฌ
Error Handling
ProblemDetail (RFC 9457 / RFC 7807)
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
ProblemDetail handleNotFound(EntityNotFoundException ex) {
ProblemDetail pd = ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND, ex.getMessage());
pd.setTitle("Resource Not Found");
pd.setProperty("timestamp", Instant.now());
return pd;
}
@ExceptionHandler(BusinessException.class)
ProblemDetail handleBusiness(BusinessException ex) {
return ProblemDetail.forStatusAndDetail(
HttpStatus.UNPROCESSABLE_ENTITY, ex.getMessage());
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatusCode status, WebRequest request) {
ProblemDetail pd = ProblemDetail.forStatus(status);
pd.setTitle("Validation Failed");
pd.setProperty("errors", ex.getBindingResult().getFieldErrors().stream()
.map(e -> Map.of("field", e.getField(), "message", e.getDefaultMessage()))
.toList());
return ResponseEntity.status(status).body(pd);
}
}
Enable: spring.mvc.problemdetails.enabled=true
Custom Validation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FutureBusinessDayValidator.class)
public @interface FutureBusinessDay {
String message() default "Must be a future business day";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class FutureBusinessDayValidator
implements ConstraintValidator<FutureBusinessDay, LocalDate> {
@Override
public boolean isValid(LocalDate value, ConstraintValidatorContext ctx) {
if (value == null) return true;
return value.isAfter(LocalDate.now())
&& value.getDayOfWeek().getValue() <= 5;
}
}
DTO with Validation (Record)
public record CreateOrderRequest(
@NotBlank @Size(max = 200) String name,
@NotNull @Positive BigDecimal amount,
@NotNull @FutureBusinessDay LocalDate dueDate,
@NotEmpty List<@NotBlank String> items) {}
Production Defaults
spring:
mvc:
problemdetails:
enabled: true
jackson:
default-property-inclusion: non_null
deserialization:
fail-on-unknown-properties: false
lifecycle:
timeout-per-shutdown-phase: 30s
server:
shutdown: graceful
tomcat:
max-threads: 200
accept-count: 100
connection-timeout: 5s
Cross-References
| Topic | Skill |
|---|
| JPA/Hibernate, Spring Data | jpa-patterns |
| REST API design principles | api-design |
| Virtual Threads, Records, Sealed Types | java-modern-patterns |
| Spring Security | springboot-security |
| TDD, MockMvc, JUnit 5 | springboot-tdd |
| PR/deploy verification | springboot-verification |
| Kotlin + Spring Boot | kotlin-patterns |
| SQL query optimization | sql-optimization-patterns |
Verification
์ฝ๋ ์์ฑ ํ ๋ฐ๋์ ์คํ:
./gradlew build
./gradlew bootRun
Gotchas
- โ
@Autowired ํ๋ ์ฃผ์
์ฌ์ฉ โ ์์ฑ์ ์ฃผ์
ํ์
- โ application.yml์ ๋ฏผ๊ฐ ์ ๋ณด ํ๋์ฝ๋ฉ โ ํ๊ฒฝ๋ณ์ ๋๋ Vault
- โ
@RestController์์ ์ํฐํฐ ์ง์ ๋ฐํ โ DTO๋ก ๋ณํ ํ์
- โ
@Configuration ํด๋์ค์ ๋น์ฆ๋์ค ๋ก์ง โ ์ค์ ๋ง ๋ด์ ๊ฒ