#컴포넌트 스캔과 의존관계 자동 주입
- 지금까지 스프링 빈을 등록할때 일일히 자바 코드(@Bean)이나 XML(<bean>)을 통해 등록하였다.
- 실무에 가서 스프링빈이 수십, 수백개가 될 수도 있는데 이는 설정 정보도 너무 커지고, 누락의 문제도 발생할 수 잇다.
: So, 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 Component Scan이라는 기능과 의존 관계도 자동으로 주입하는 @Autowired라는 기능도 제공한다.
Ex) 자동으로 빈을 등록하는 AutoAppConfig
@Configuration
@ComponentScan(
//제외할 클래스를 명시 할 수 있다.
excludeFilters= @Filter(type=FilterType.ANNOTATION, classes= Configuration.class))
public class AutoAppConfig{
}
+) 기존의 @Configuration의 설정 정보를 이용하면 중복 실행 가능성이 있기 때문에 제외하기 위해 ExcludeFilter를 사용했다. 해당 연습에서만 그럴 예정..
- ComponentScan은 @Component 애노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다.
@Component만: MemoryMemberRepository, RateDiscountPolicy (만들어둔 구현체 중 client에 주입할 클래스에 붙이면 됨), @Component, @Autowired 추가 : MemberServiceImpl, OrderServiceImpl (의존관계를 주입 받아야할 클래스에 붙임)
#작동 과정
- @ComponentScan은 @Component가 붙은 모든 클래스를 스프링 빈으로 등록한다.
- 기본 빈 이름을 사용해도 되고, @Component("빈 이름")으로 빈 이름을 지정해도 된다.
- 생성자에 @Autowired를 지정하면 스프링 컨테이너가 자동으로 스프링 빈을 찾아서 주입한다.
: 기본적으로 타입이 같은 빈을 찾아서 주입한다. 생성자에 파라미터가 여러개여도 자동으로 모두 주입한다.
#탐색 위치와 기본 스캔 대상
- 모든 자바 클래스를 모두 컴포넌트 스캔하려면 시간이 오래 걸린다. 따라서 꼭 필요한 위치부터 탐색하도록 지정가능하다.
@ComponentScan(
basePackage="hello.core"
)
: 만약 따로 지정하지 않으면, @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
- 권장하는 방법은 패키지 위치를 따로 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이다.
: 이렇게 하면 해당 패키지를 포함한 하위 부분이 모두 자동으로 컴포넌트 스캔의 대상이 된다.
+) Spring Boot를 사용하면 스프링 부트의 대표적인 시작 정보인 @SpringBootApplication을 프로젝트 시작 루트 위치에 두는 것이 관례이며, 이 설정 안에 @ComponentScan이 포함되어있다.
#컴포넌트 스캔 기본 대상
: 컴포넌트 스캔은 @Component뿐만 아니라 다음의 내용도 추가로 대상에 포함한다.
- @Component : 컴포넌트 스캔에 사용
- @Controller : 스프링 MVC 컨트롤러에서 사용
- @Service : 스프링 비즈니스 로직에서 사용
- @Repository : 스프링 데이터 접근 계층에서 사용
- @Configuration : 스프링 설정 정보에서 사용, 스프링 빈이 싱글톤을 유지하도록 해준다.
#Filter
- includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
- excludeFilters : 컴포넌트 스캔 에서 제외할 대상을 지정한다.
-> 예시를 통해 확인해보자
1) 컴포넌트 스캔 대상에 추가할 애노테이션 @MyIncludeComponent를 만든다.
2) 컴포넌트 스캔 대상에서 제외할 애노테이션 @MyExcludeComponent를 만든다.
3) BeanA에 @MyIncludeComponent를 적용한다
4) BeanB에 @MyExcludeComponent를 적용한다.
5) Test를 통해 확인한다.
public class ComponentFilterAppConfigTest{
@Test
void filterScan(){
Applicaion ac=new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class);
//BeanA는 등록되었고, BeanB는 따로 등록되지 않았다.
assertThat(beanA).isNotNull();
Assertions.assertThrows(
NoSuchBeanDefinitionException.class,
() -> ac.getBean("beanB", BeanB.class));
}
@Configuration
@ComponentScan(
includeFilters=@Filter(type=FilterType.ANNOTATION,class=MyIncludeComponent.class),
excludeFilters=@Filter(type=FilterType.ANNOTATION,class=MyExcludeComponent.class)
)
static class ComponentFilterAppConfig{}
}
'Web > Java (Spring+JSP)' 카테고리의 다른 글
JWT을 활용한 로그인/ Interceptor를 활용한 인가 처리 구현 (0) | 2022.03.11 |
---|---|
🍃 Spring Boot로 개발한 Restful API 작동 프로세스 (0) | 2022.03.03 |
Spring 핵심 원리 #8- 싱글톤 컨테이너 (0) | 2022.01.12 |
Spring 핵심 원리 #7- 스프링 컨테이너 관련 인터페이스 (0) | 2022.01.11 |
Spring 핵심 원리 #6- 스프링 컨테이너 생성과 등록된 빈 조회 (0) | 2022.01.07 |