Back to til
Aug 05, 2025
6 min read

[TIL] 2025-08-05 | Spring 핵심 개념과 Validation

1. 오늘 학습한 내용

1.1. Spring 숙련 1주차

1.1.1. Spring의 핵심 개념

  • Spring Container
    • 객체를 생성 및 관리하고 의존성을 주입하는 역할을 담당
      • Spring Container를 이용하면 객체를 직접 생성하는 코드를 만들지 않기 때문에 객체 간의 의존성 및 결합도가 높아짐
    • 싱글톤 패턴의 문제점들을 해결하면서 객체를 싱글톤으로 관리함
      • 기본적으로 싱글톤이지만, 요청할 때마다 새로운 객체를 생성해서 반환하는 기능도 제공
  • Spring Container의 종류
    • BeanFactory
      • 최상위, 핵심 인터페이스
      • Spring Bean을 관리하고 조회
    • ApplicationContext
      • BeanFactory를 확장한 인터페이스
      • Application 개발에 필요한 다양한 기능을 추가적으로 제공
        • AOP, 국제화, 환경변수 분리, 이벤트 발행, 리소스 로딩, 자동 후처리기 등록 등
      • 일반적으로 ApplicationContext를 Spring Container라고 표현
  • Spring Bean
    • Spring Container가 생성하고 관리하는 Java 객체
    • 기본적으로 Singleton으로 설정
      • Singleton: 클래스의 인스턴스가 오직 하나만 생성되도록 보장하는 디자인 패턴
        • 상태 유지를 하면 안 됨 → 무상태로 설계
    • 의존성 주입(DI)를 통해 다른 객체들과 의존 관계를 맺을 수 있음
    • 생성, 초기화, 사용, 소멸의 생명주기를 가짐
  • Bean 등록 방법
    • 자동 - Java Annotation
      • @Component Scan+@Component 등
      • 보통 직접 개발한 클래스
    • 수동 - Java Config, XML
      • @Configuration+@Bean
      • 보통 외부 라이브러리, 조건부/동적 설정이 필요한 객체

1.1.2. IoC와 DI

  • IoC (Iversion Of Control, 제어의 역전)
    1. 객체의 생성 및 생명주기 관리를 개발자가 직접 하는 것이 아니라 컨테이너가 담당
    2. 객체 간의 결합도를 낮춰 유연한 코드
    3. 테스트 가능성을 높여줌
  • DI(Dependency Injection, 의존성 주입)
    • IoC를 구현하는 방식 중 하나로 해당 객체를 직접 생성하지 않고 Spring이 주입해주는 방식

1.1.3. Spring Bean 등록

  • 특정 패키지 내에서 @Component, @Service, @Repository, @Controller 같은 Annotation이 붙은 클래스를 자동으로 검색하고, 이를 Bean으로 등록하는 기능
  • @ComponentScan
    • @SpringBootApplication도 @ComonentScan을 가지고 있음
    • @ComponentScan의 속성
      • basePackages: 특정 패키지를 스캔할 때 사용, 배열로 여러개를 선언할 수 있음
        • 예시: @ComponentScan(basePackages = {"com.example", "com.another"})
      • basePackageClasses: 특정 클래스가 속한 패키지를 기준으로 스캔할 수 있음
        • 예시: @ComponentScan(basePackageClasses = MyApp.class)
      • excludeFilters: 스캔에서 제외할 클래스를 필터링할 수 있음
        • 예시: @ComponentScan(excludeFilters = @ComponentScan.Filter(SomeClass.class))
      • includeFilters: 특정 조건에 맞는 클래스만 스캔하여 포함할 수 있음
        • 예시: @ComponentScan(includeFilters = @ComponentScan.Filter(Service.class))
    • @ComponentScan의 동작 순서
      1. Spring Application이 실행되면 @ComponentScan이 지정된 패키지를 탐색한다.
      2. 해당 패키지에서 @Component 또는 Annotation이 붙은 클래스를 찾습니다.
      3. 찾은 클래스를 Spring 컨테이너에 빈으로 등록합니다.
      4. 등록된 빈은 **의존성 주입(DI)**과 같은 방식으로 다른 빈과 연결됩니다.
  • Bean 충돌
    • 같은 이름의 Bean 등록
      • 자동 Bean 등록 VS 자동 Bean 등록 → ConflictingBeanDefinitionException 발생
      • 수동 Bean 등록 VS 자동 Bean 등록 → 수동으로 등록한 Bean
        • Spring Boot에서는 오류 발생
        • spring.main.allow-bean-definition-overriding=true 을 통해 허용 가능
    • 같은 타입의 Beam 등록
      1. @Autowired+필드명
      2. @Quailifer
      3. @Primary
        • 우선 순위 부여, 제일 많이 사용

1.1.4. 의존관계 주입

  • @Autowired
    • 의존성을 자동으로 주입할 때 사용하는 Annotation
    • Spring Bean으로 등록되어 있어야 사용 가능
  1. 생성자 주입
    • 최초에 한번 생성된 후 값이 수정되지 못함 → 불변성 보장
    • 생성자가 하나인 경우 @Autowired 생략이 가능
    • 컴파일 시점에 오류를 알 수 있음 → 의존성 누락 방지, 순환 참조 방지
    • final 키워드 사용 가능
    • Lombok @RequiredArgsConstructor와 결합하면 편리하게 사용 가능
      • all final and non-null fields 를 만족하는 필드를 컴파일 시점에 자동으로 생성자를 만들어줌
    • 순수 Java 코드로 Test 용이
  2. setter 주입
    • 선택하거나, 변경 가능한 의존관계에 사용
    • final 키워드 불가
  3. 필드 주입
    • 코드는 간결하지만 Spring이 없으면 사용 불가
      • Spring에 의존해야 하기 때문에 테스트가 힘듦

1.1.5. Validation

  • 시스템이 미리 정의한 사양(specification)에 부합하고 있는지 검증하는 것
    1. 검증을 통해 적절한 메세지유저에게 보여주어야 한다.
    2. 검증 오류로 인해 정상적인 동작을 하지 못하는 경우는 없어야 한다.
    3. 사용자가 입력한 데이터는 유지된 상태여야 한다.
  • 종류
    1. 클라이언트
    2. 서버
      • API Spec 정의 및 개발
    3. 데이터베이스
      • 제약조건 사용
  • BindingResult
    • Errors 인터페이스를 상속받은 인터페이스
    • 에러의 저장과 조회 기능을 제공
    • BindingResult 파라미터는 검증대상 파라미터 뒤에 위치

1.1.6. Bean Validation

  • 특정 필드 검증의 경우 빈값, 길이, 크기, 형식 과 같은 간단한 로직인데, 이러한 로직들을 모든 프로젝트에 적용할 수 있도록 표준화 한 것
    • Java Annotation을 기반으로 Validation
  • BindingResult로 인해 컨트롤러가 비대해지는 것을 막아주고 편리하게 사용 가능
  • Bean Validation은 기술 표준 인터페이스
  • 다양한 Annotation들과 여러가지 Interface로 구성되어 있음
    • Bean Validation(인터페이스) 구현체인 Hibernate Validator를 사용
  • 주요 Annotation
    • @NotBlank
      1. null을 허용하지 않는다.
      2. 공백(” “)을 허용하지 않는다. 하나 이상의 문자를 포함해야한다.
      3. 빈값(””)을 허용하지 않는다.
      4. CharSequence 타입 허용
        • String은 CharSequence(Interface)의 구현체이다.
    • @NotNull
      1. null을 허용하지 않는다.
      2. 모든 타입을 허용한다.
    • @NotEmpty
      1. null을 허용하지 않는다.
      2. 빈값(””)을 허용하지 않는다.
      3. CharSequence, Collection, Map, Array 허용
  • 동작 순서
    • Spring Boot Application 실행 시 자동으로 Bean Validator가 통합된다.
    1. LocalValidatorFactoryBean 을 Global Validator로 등록한다.

    2. Global Validator가 Default로 적용되어 있으니 @Valid, @Validated 만 적용하면 된다.

    3. Bean Validation Annotation이 있으면 검증을 수행한다.

      ex) @NotNull, @NotBlank, @Max 등등..

    4. Validation Error가 발생하면 FieldError, ObjectError를 생성하여 BindingResult에 담아준다.

  • @Valid, @Validated 차이점
    1. @ValidJava 표준이고 @ValidatedSpring 에서 제공하는 Annotation이다.
    2. @Validated 를 통해 Group Validation 혹은 Controller 이외 계층에서 Validation이 가능하다.
      • 역으로 Controller 외에서는 @Validated 사용
    3. @ValidMethodArgumentNotValidException 예외를 발생시킨다.
    4. @ValidatedConstraintViolationException 예외를 발생시킨다.
  • Bean Validation을 여러 개 적용해야 하는 경우
    • 대부분 DTO를 분리해서 사용하면 해결됨
    • groups
  • @ModelAttribute와 @RequestBody 의 Bean Validation 차이점
    1. @ModelAttribute
      • 각각의 필드 단위로 바인딩
      • 특정필드 변환 실패
        • 컨트롤러 호출, 나머지 필드 Validation 적용
    2. @RequestBody
      • 필드별로 적용되는것이 아니라 객체 단위로 적용
      • 특정필드 변환 실패 → Object 변환 실패
        • 컨트롤러 미호출, Validation 미적용

2. 더 알아볼 내용 / 다음에 할 내용

  • SOLID (객체 지향 설계 5원칙)
  • @Configuration에서 @Bean을 통해 등록하는 것과 일반 @Component 클래스에서 @Bean을 등록하는 것의 차이 → CGLIB 프록시 객체
  • IoC를 구현하는 DI 이외의 다른 방법