본문 바로가기

프로그래밍/Spring

[Spring] 6. 컴포넌트 스캔

컴포넌트 스캔과 의존관계 자동 주입 시작하기

  • 스프링 빈을 등록할 때 자바 코드의 @Bean이나 XML의 <bean> 태그를 통해서 설정 정보에 직접 등록할 스프링 빈을 나열
  • 그런데 이렇게 등록해야할 빈이 수십, 수백 개가 되면 직접 등록하는 데에 한계가 있다.
  • 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능 제공
  • 의존관계를 자동으로 주입하는 @Autowired라는 기능을 제공한다.

컴포넌트 스캔

@Configuration
@ComponentScan(
//basePackages = "com.example.core.discount",
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
                Configuration.class)) //appconfig와 설정정보 겹치기 때문에 제외
public class AutoAppConfig {}

@ComponentScan 은 @Component 가 붙은 모든 클래스를 스프링 빈으로 등록한다

  • 이제 각 클래스가 컴포넌트 스캔의 대상이 되도록 @Component 애노테이션을 붙여주면 된다.
    MemoryMemberRepository @Component 추가
    RateDiscountPolicy @Component 추가

@Configuration 이 컴포넌트 스캔의 대상이 된 이유도 @Configuration 소스코드를 열어보면 @Component 애노테이션이 붙어있기 때문이다.

 

@Autowired

@Component
  public class MemberServiceImpl implements MemberService {
      private final MemberRepository memberRepository;
      @Autowired
      public MemberServiceImpl(MemberRepository memberRepository) {
          this.memberRepository = memberRepository;
      }
}

 

@Autowired 는 의존관계를 자동으로 주입해준다. 

@Autowired 를 사용하면 생성자에서 여러 의존관계도 한번에 주입받을 수 있다

 

 

 

탐색 위치와 기본 스캔 대상

탐색할 패키지의 시작 위치 지정

  • 모든 자바 클래스를 다 컴포넌트에 스캔하면 시간이 오래 걸리기 때문에 필요한 위치부터 탐색하도록 시작 위치를 지정할 수 있다.
  • backPackages : 탐색할 패키지의 시작 위치를 지정한다.
  • 해석하자면, “hello.core” 패키지를 포함해서 하위 패키지를 모두 탐색한다는 의미이다.
    • basePackages = {"hello.core", "hello.service"} 처럼 여러 시작 위치를 지정할 수도 있다.
@ComponentScan(
          basePackageClasses = AutoAppConfig.class,
}
  • basePackageClasses : 지정한 클래스의 패키지를 탐색 시작 위치로 지정한다.
  • 패키지의 시작 위치를 지정하지 않으면 @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
권장하는 방법은 패키지의 위치를 지정하지 않고,
설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이다. 스프링 부트도 이 방법을 기본으로 제공한다.

 

  • 예를 들어 프로젝트가 다음과 같은 구조로 되어 있으면
    • com.hello
    • com.hello.service
    • com.hello.repository
  • com.hello 를 프로젝트 시작 루트로 하고, 여기에 AppConfig와 같은 메인 설정 정보를 두고, @ComponentScan 애노테이션을 붙이고, basePackages 지정은 생략한다.
  • 그러면 com.hello 를 포함한 하위 패키지 모두 자동으로 컴포넌트 스캔의 대상이 된다.

컴포넌트 스캔 기본 대상

  • 컴포넌트 스캔은 Component 뿐만 아니라 다음과 같은 내용도 추가로 대상에 포함한다.
    • @Contoller : 스프링 MVC 컨트롤러에서 사용
    • @Service : 스프링 비즈니스 로직에서 사용
    • @Repository : 스프링 데이터 접근 계층에서 사용
    • @Configuration : 스프링 설정 정보에서 사용

필터

  • includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
  • excluderFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.

중복 등록과 충돌

  • 컴포넌트 스캔에서 같은 빈 이름을 등록하는 두가지 상황이 있다. 결론적으로 둘다 오류가 발생한다.
  1. 자동 빈 등록 vs 자동 빈 등록 -> 같은 경우 스프링은 ConflictingBeanDefinitionException 와 같은 예외를 발생시킨다.
  2. 수동 빈 등록 vs 자동 빈 등록 -> 같은 경우 수동 빈 등록이 우선권을 가지면서 자동 빈을 오버라이딩 한다.
Consider renaming one of the beans or enabling overriding by setting 
spring.main.allow-bean-definition-overriding=true

스프링 부트에서 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 기본 값

 

 

출처 : 김영한 스프링 핵심 원리