컴포넌트 스캔, 의존 관계 자동 주입
지금까지는 스프링 빈을 등록할 때는 설정 정보(Config)에 직접 등록할 스프링 빈을 나열했다.
스프링 빈을 @Bean을 통해서 일일이 등록을 할 수 있지만, 이렇게 되면 굉장히 귀찮게 된다.
이를 해결하기 위해, 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔 기능을 제공한다.
또한, 의존 관계를 자동으로 주입하는 @Autowired 기능도 제공한다.
@ComponentScan
지금까지 사용한 AppConfig를 유지하며, 새로운 AutoAppConfig를 만들어보자.
@Configuration
@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class))
public class AutoAppConfig {
}
컴포넌트 스캔을 사용하려면 @ComponentScan을 붙혀주면 된다.
기존의 AppConfig와 달리 @Bean으로 등록한 클래스가 하나도 없다.
( 컴포넌트 스캔 옆에 excludeFilters ... 은 컴포넌트 스캔을 사용하면 @Configuration이 붙은 설정 정보도 다 자동으로 등록되어서 기존에 공부를 위해 만들었던 AppConfig, TestConfig 등이 다 등록되므로, 이를 방지하기 위해 설정 정보를 컴포넌트 스캔 대상에서 제외하였다. )
컴포넌트 스캔은 이름 그대로 @Component 애노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다.
각 클래스가 컴포넌트 스캔의 대상이 되도록 @Component 를 붙혀주면 된다.
EX)
@Component
public class MemoryMemberRepository implements MemberRepository {}
@Component
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
이전에 AppConfig에서는 @Bean 으로 직접 설정 정보를 작성했고, 의존관계도 직접 명시했다. 이제는 이런 설정 정보 자체가 없기 때문에, 의존관계 주입도 이 클래스 안에서 해결해야 한다.
@Autowired는 의존관계를 자동으로 주입해준다. ( 생성자에 붙혀줌 )
@ComponentScan 은 @Component 가 붙은 모든 클래스를 스프링 빈으로 등록한다.
스프링 빈의 기본 이름은 클래스 명을 사용하되, 맨 앞글자만 소문자로 사용한다.
( MemberServiceImpl → memberServiceImp )
@Autowired 를 생성자에 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입해준다.
이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입해준다. ( getBean(MemberRepository.class) 와 동일 )
탐색 위치와 기본 스캔 대상
탐색할 패키지의 시작 위치를 지정할 수 있다.
@ComponentScan( basePackages = "hello.core" }
와 같이 basePackages 를 통해 탐색할 패키지의 시작 위치를 지정할 수 있다. 해당 패키지를 포함하여 하위 패키지를 모두 스캔하게 된다.
만약 지정하지 않으면, @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
→ 때문에, basePackages 옵션을 사용하는 것보다 애초에 설정 정보 클래스의 위치를 프로젝트의 최상단에 두는 것이 좋다.
예를 들어,
- com.hello
- com.hello.service
- com.hello.repository
와 같이 되었다면, com.hello 인 프로젝트 시작 루트에 AppConfig와 같은 메인 설정 정보를 두고 @ComponentScan을 붙히며, basePakages 지정을 생략한다.
컴포넌트 스캔 기본 대상
- @Component : 컴포넌트 스캔에서 사용
- @Controller : 스프링 MVC 컨트롤러에서 사용
- @Service : 스프링 비지니스 로직에서 사용
- @Repository : 스프링 데이터 접근 계층에서 사용
- @Configuration : 스프링 설정 정보에서 사용
필터
- includeFilters : 컴포넌트 스캔 대상을 추가로 지정
- excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정
이와 같이 옵션을 사용해서 컴포넌트 스캔 대상에 해당 클래스를 추가하거나 제외할 수 있다.
@ComponentScan(includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
이와 같이 Config 클래스에 붙혀주면 되는데, 여기서 MyIncludeComponent, MyExcludeComponent는 따로 어노테이션을 만들어야 하고 추가, 제외할 클래스에 @MyIncludeComponent, @MyExcludeComponent 어노테이션을 추가해줘야 한다.
→ @Component면 충분, 위의 필터 옵션들을 이용할 일은 많이 없다.
FilterType 옵션
- ANNOTATION : 기본값, 애노테이션을 인식해서 동작한다
- ASSIGNABLE_TYPE : 지정한 타입과 자식 타입을 인식해서 동작한다.
- ASPECTJ : AspectJ 패턴 사용
- REGEX : 정규 표현식
- CUSTOM :TypeFilter 이라는 인터페이스를 구현해서 처리
더 자세히 알고싶은 사람들은 따로 알아보면 될 것 같다.
정리
어노테이션을 통한 자동 빈 등록의 경우, 이름이 같으면 스프링은 ConflictingBeanDefinitionException 예외가 발생한다.
수동 빈 등록과 자동 빈 등록이 충돌하게 되면, 수동 빈 등록이 우선시 된다. 그러나, 이를 통해 문제가 발생할 수 있다.
때문에 최근 스프링 부트는 수동 빈과 자동 빈 등록이 충돌하게 되면 오류가 발생하도록 변경되었다.
@ComponentScan 과 @Component, @Autowired 등을 통해서 훨씬 더 깔끔하게 코드를 작성할 수 있게 되었다.
스프링이 제공하는 어노테이션들을 잘 공부해서 적절하게 사용할 수 있도록 하자!
'Spring' 카테고리의 다른 글
Spring- 필터, 인터셉터(Filter, Interceptor) (0) | 2023.09.18 |
---|---|
Spring- 쿠키, 세션(Cookie, Session)[로그인] (0) | 2023.09.18 |
싱글톤 패턴, 싱글톤 컨테이너 (Singleton) (0) | 2023.08.02 |
스프링 컨테이너, 스프링 빈(Spring Container, Spring Bean) (0) | 2023.08.02 |
Spring Basic- Bean Scope(웹 스코프) (0) | 2023.06.10 |