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
- 보통 외부 라이브러리, 조건부/동적 설정이 필요한 객체
- 자동 - Java Annotation
1.1.2. IoC와 DI
- IoC (Iversion Of Control, 제어의 역전)
- 객체의 생성 및 생명주기 관리를 개발자가 직접 하는 것이 아니라 컨테이너가 담당
- 객체 간의 결합도를 낮춰 유연한 코드
- 테스트 가능성을 높여줌
- 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))
- 예시:
- basePackages: 특정 패키지를 스캔할 때 사용, 배열로 여러개를 선언할 수 있음
- @ComponentScan의 동작 순서
- Spring Application이 실행되면
@ComponentScan이 지정된 패키지를 탐색한다. - 해당 패키지에서
@Component또는 Annotation이 붙은 클래스를 찾습니다. - 찾은 클래스를 Spring 컨테이너에 빈으로 등록합니다.
- 등록된 빈은 **의존성 주입(DI)**과 같은 방식으로 다른 빈과 연결됩니다.
- Spring Application이 실행되면
- Bean 충돌
- 같은 이름의 Bean 등록
- 자동 Bean 등록 VS 자동 Bean 등록 →
ConflictingBeanDefinitionException발생 - 수동 Bean 등록 VS 자동 Bean 등록 → 수동으로 등록한 Bean
- Spring Boot에서는 오류 발생
spring.main.allow-bean-definition-overriding=true을 통해 허용 가능
- 자동 Bean 등록 VS 자동 Bean 등록 →
- 같은 타입의 Beam 등록
- @Autowired+필드명
- @Quailifer
- @Primary
- 우선 순위 부여, 제일 많이 사용
- 같은 이름의 Bean 등록
1.1.4. 의존관계 주입
@Autowired- 의존성을 자동으로 주입할 때 사용하는 Annotation
- Spring Bean으로 등록되어 있어야 사용 가능
- 생성자 주입
- 최초에 한번 생성된 후 값이 수정되지 못함 → 불변성 보장
- 생성자가 하나인 경우
@Autowired생략이 가능 - 컴파일 시점에 오류를 알 수 있음 → 의존성 누락 방지, 순환 참조 방지
final키워드 사용 가능- Lombok
@RequiredArgsConstructor와 결합하면 편리하게 사용 가능- all final and non-null fields 를 만족하는 필드를 컴파일 시점에 자동으로 생성자를 만들어줌
- 순수 Java 코드로 Test 용이
- setter 주입
- 선택하거나, 변경 가능한 의존관계에 사용
final키워드 불가
- 필드 주입
- 코드는 간결하지만 Spring이 없으면 사용 불가
- Spring에 의존해야 하기 때문에 테스트가 힘듦
- 코드는 간결하지만 Spring이 없으면 사용 불가
1.1.5. Validation
- 시스템이 미리 정의한 사양(specification)에 부합하고 있는지 검증하는 것
- 검증을 통해 적절한 메세지를 유저에게 보여주어야 한다.
- 검증 오류로 인해 정상적인 동작을 하지 못하는 경우는 없어야 한다.
- 사용자가 입력한 데이터는 유지된 상태여야 한다.
- 종류
- 클라이언트
- 서버
- API Spec 정의 및 개발
- 데이터베이스
- 제약조건 사용
BindingResult- Errors 인터페이스를 상속받은 인터페이스
- 에러의 저장과 조회 기능을 제공
- BindingResult 파라미터는 검증대상 파라미터 뒤에 위치
1.1.6. Bean Validation
- 특정 필드 검증의 경우 빈값, 길이, 크기, 형식 과 같은 간단한 로직인데, 이러한 로직들을 모든 프로젝트에 적용할 수 있도록 표준화 한 것
- Java Annotation을 기반으로 Validation
- BindingResult로 인해 컨트롤러가 비대해지는 것을 막아주고 편리하게 사용 가능
- Bean Validation은 기술 표준 인터페이스
- 다양한 Annotation들과 여러가지 Interface로 구성되어 있음
- Bean Validation(인터페이스) 구현체인 Hibernate Validator를 사용
- 주요 Annotation
- @NotBlank
- null을 허용하지 않는다.
- 공백(” “)을 허용하지 않는다. 하나 이상의 문자를 포함해야한다.
- 빈값(””)을 허용하지 않는다.
- CharSequence 타입 허용
- String은 CharSequence(Interface)의 구현체이다.
- @NotNull
- null을 허용하지 않는다.
- 모든 타입을 허용한다.
- @NotEmpty
- null을 허용하지 않는다.
- 빈값(””)을 허용하지 않는다.
- CharSequence, Collection, Map, Array 허용
- @NotBlank
- 동작 순서
- Spring Boot Application 실행 시 자동으로 Bean Validator가 통합된다.
-
LocalValidatorFactoryBean을 Global Validator로 등록한다. -
Global Validator가 Default로 적용되어 있으니
@Valid,@Validated만 적용하면 된다. -
Bean Validation Annotation이 있으면 검증을 수행한다.
ex) @NotNull, @NotBlank, @Max 등등..
-
Validation Error가 발생하면
FieldError,ObjectError를 생성하여BindingResult에 담아준다.
- @Valid, @Validated 차이점
@Valid는 Java 표준이고@Validated는 Spring 에서 제공하는 Annotation이다.@Validated를 통해 Group Validation 혹은 Controller 이외 계층에서 Validation이 가능하다.- 역으로 Controller 외에서는 @Validated 사용
@Valid는MethodArgumentNotValidException예외를 발생시킨다.@Validated는ConstraintViolationException예외를 발생시킨다.
- Bean Validation을 여러 개 적용해야 하는 경우
- 대부분 DTO를 분리해서 사용하면 해결됨
- groups
- @ModelAttribute와 @RequestBody 의 Bean Validation 차이점
- @ModelAttribute
- 각각의 필드 단위로 바인딩
- 특정필드 변환 실패
- 컨트롤러 호출, 나머지 필드 Validation 적용
- @RequestBody
- 필드별로 적용되는것이 아니라 객체 단위로 적용
- 특정필드 변환 실패 → Object 변환 실패
- 컨트롤러 미호출, Validation 미적용
- @ModelAttribute
2. 더 알아볼 내용 / 다음에 할 내용
- SOLID (객체 지향 설계 5원칙)
- @Configuration에서 @Bean을 통해 등록하는 것과 일반 @Component 클래스에서 @Bean을 등록하는 것의 차이 → CGLIB 프록시 객체
- IoC를 구현하는 DI 이외의 다른 방법