Spring

컴포넌트 스캔 (@ComponentScan)

녁이 2023. 8. 2. 19:26
728x90
반응형

컴포넌트 스캔, 의존 관계 자동 주입

지금까지는 스프링 빈을 등록할 때는 설정 정보(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 등을 통해서 훨씬 더 깔끔하게 코드를 작성할 수 있게 되었다.

스프링이 제공하는 어노테이션들을 잘 공부해서 적절하게 사용할 수 있도록 하자!

 

728x90
반응형