1. 컴포넌트 스캔과 의존관계 자동 주입
- 지금까진 설정정보에 직접 수동적으로 등록 하는 정보를 나열하는 방식을 취함
- 실무에서는 이를 일일히 등록하기 어려우며, 설정정보 어렵고 누락하는 위험성 존재
- 무엇보다 빈을 등록하는 일이 반복된다.
스프링은 그래서
- 스프링은 설정정보가 없어도 스프링 빈을 자동적으로 등록해주는 컴포넌트 스캔 제공
- 의존성을 자동으로 주입해주는 @Autowired라는 기능도 제공
새롭게 설정정보 지정해주기
- 설정 정보니깐
@Configuration
붙여주기
컴포넌트 스캔이란?
- 스프링 빈을 쫙 끌어와서 자동적으로 빈을 끌어올리는 작업
- @ComponentScan
이라는 어노테이션을 컴포넌트 스캔 기능을 위해 추가
- 어노테이션 붙은 빈 찾아서 등록해주는 과정을 거침
- 컴포넌트 스캔을 통해서 자동으로 지정해줄 때, 빼줄 빈도 선언이 가능
excludeFilters를 통해서 우리는 기존 예제코드들을 (ex AppConfig) 를 제외해주기 위해서 이를 스캔 대상에서 제외시킨다고 작성해준다.
(+) 실무에서는 굳이 이렇게 안하고, 컴포넌트 스캔으로 처리한다
=> 이렇게 해주면 @Bean 처럼 하나하나 빈으로 등록해주지 않아도 된다.
- 이제 빈 등록하지 않고,빈으로 등록하고자 하는 클래스 위에 @Component를 붙여주면 나중에 컴포넌트 스캔이 쫙 돌면서 @Component가 들어가있는 클래스들을 자동으로 등록해주게 됩니다.
=> 구현체들 중 DiscountPolicy 를 구현한 두개 중 내가 사용할, 빈으로 등록할 것에 @Component를 붙여주면서 빈 등록을 진행하면 된다.
그런데 컴포넌트 스캔은 설정정보 지정란이 존재하지 않지
- 기존에는 @Configuration에서 의존관계를 설정해주었음 but 컴포넌트 스캔 사용할 때는 바로 빈으로 등록해버린다.
- 즉, 이전에는 설정 정보를 작성해줬었는데 이제는 설정 정보 존재하지 않아서, 의존관계 주입 설정은 빈으로 등록해준 클래스 안에서 구현해야 한다.
그러면 의존성 주입은 how ?
- 빈으로 등록할 때 생성자에 @Autowired 어노테이션을 붙여주게 된다면 생성자에 존재하는 의존관계를 자동적으로 등록해준다.
- 즉 클래스 생성할 때 의존관계를 주입해주는 것!
- 따라서 @ComponentScan을 쓰면 @Autowired를 붙여줌으로써, 자동적으로 맵핑이 되게 하는 동시에 의존성 관계 또한 주입해주게 된다.
이전과 달라진 과정
- 설정정보로 AppConfig에 이것저것 등록해주지 않고, 단순히 @ComponentScan이 붙은 AutoAppConfig라는 클래스로 설정정보 넘겨준다.
컴포넌트 스캔 (@ComponentScan) 의 과정
- @ComponentScan은 @Component가 붙은 클래스를 다 뒤진다
- @Componen 붙은 애를 싱글톤 + 빈으로 등록
- 이때 저장되는 이름 방식
=> 기본 이름은 클래스명, 앞 글자는 소문자로 변경하기!
의존관계 자동 주입 (@Autowired) 과정
- 생성자에 @Autowired 지정 시, 스프링 컨테이너가 자동으로 해당 스프링 빈 찾아 주입
- 기본 전략은 타입이 같은 빈!
- 생성자에 파라미터 많더라도, 자동으로 주입
2. @ComponentScan 탐색 위치와 기본 스캔 대상
2-1 탐색할 패키지의 시작 위치 지정
- @ComponentScan 에게 스캔을 시작할 패키지를 지정할 수 있음
- basePackages : 패키지 지정하면 상위패키지부터 하위패키지로 돌면서 스캔 진행
- basePackageClasses : 지정한 클래스의 패키지를 탐색 시작 위치로 지정
- 아무것도 지정안할 시 (디폴트) :
@ComponentScan
이 붙은 설정 정보 클래스의 패키지가 시작 위치 => 설정 정보 클래스의 위치를 프로젝트 최상단에
프로젝트메인 설정 정보는 프로젝트를 대표하는 정보, 따라서 프로젝트 시작 루트 위치에 두는 것이 권장됨 / 스프링부트로 진행하면 스프링 부트의 대표 시작 정보인 @SpringBootApplication를 프로젝트 시작 루트에 두는 것이 관례
2-2 : 컴포넌트 스캔 기본 대상
- @Component : 컴포넌트 스캔에서 사용
- @Controlller : 스프링 MVC 컨트롤러에서 사용 & 스프링 MVC 컨트롤러로 인식
- @Repository : 스프링 데이터 접근 계층에서 사용 & 인식 , 데이터 계층의 예외를 스프링 예외로 변환
- 특정 db에서 예외가 나타나게 되는 경우 존재
- 이걸 스프링 예외로 변환안해주고, 데이터 계층 예외로 처리하면 나중에 db가 변할 때마다 스프링 안의 로직들이 흔들리게 됨
- 따라서 해당 로직들의 견고함을 위해서 스프링 예외로 변경해주는 과정을 처리
- @Configuration : 스프링 설정 정보에서 사용 & 인식, 스프링 빈이 싱글톤으로 유지될 수 있도록 추가 처리
- @Service : 스프링 비즈니스 로직에서 사용, 별다른 역할은 없고 개발자들에게 비즈니스 로직이 여기 존재한다는 것을 인식시켜주는 용도
3. 필터
3-1 : 어노테이션 만들기
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
3-2 : 클래스에 방금 만든 두개의 어노테이션 붙여주기
@MyIncludeComponent
public class BeanA {
}
@MyExcludeComponent
public class BeanB{
}
3-3 : 필터를 돌릴 떼
@Configuration
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
)
static class ComponentFilterAppConfig {
}
- includeFilters 에 MyIncludeComponent 애노테이션을 추가해서 BeanA가 스프링 빈에 등록 o
- excludeFilters 에 MyExcludeComponent 애노테이션을 추가해서 BeanB는 스프링 빈에 등록 x
교재 왈 : 최근 스프링 부트는 컴포넌트 스캔을 기본으로 제공하는데, 개인적으로는 옵션을 변경하면서 사용하기 보다는 스프링의 기본 설정에 최대한 맞추어 사용하는 것을 권장하고, 선호
4. 중복 등록과 충돌
4-1 : 같은 빈 이름을 등록
1. 자동 빈 등록 vs 자동 빈 등록
=> ConflictingBeanDefinitionException 예외가 발생
2. 수동 빈 등록 vs 자동 빈 등록
=> 수동 빈 등록이 우선권
=> 그러나 이런 잠정적인 위험성을 가지고 있는 에러가 더 위험한 법