본문 바로가기

Backend/Spring

[Spring] 컴포넌트 스캔 1) 컴포넌트 스캔과 의존관계 주입

728x90

 

목차

  • 컴포넌트 스캔 - 컴포넌트 스캔과 의존관계 자동 주입 시작하기 
  • 컴포넌트 스캔 - 탐색 위치와 기본 스캔 대상
  • 컴포넌트 스캔 - 필터
  • 컴포넌트 스캔 - 중복 등록과 충돌

 

의존 관계 자동 주입 

 

지금까지는 @Bean이나 <bean>을 이용해 설정 정보(appConfig)에 직접 등록할 스프링 빈을 작성했다.

빈의 수가 많아지면, 등록하기도 귀찮고, 많고, 누락문제가 발생한다.

그래서 스프링은 다음과 같은 기능을 제공한다.

  • 컴포넌트 스캔 : 스프링 설정 정보 없이 자동으로 스프링 빈을 등록해주는 기능
  • 자동 의존관계 주입(@Autowired) : 의존관계(DI)를 자동으로 주입

 

즉, 컴포넌트 스캔이란,

AppConfig에 @Bean으로 등록하지 않아도, 자동으로 스프링 빈으로 등록되게 해주는 방법이며,

자동 의존관계 주입이란,

@Bean 이 있는 method에서 매개변수를 이용해 의존관계를 표현했다면, 이제는 @Autowired를 이용하여, 의존성을 타내준다.

 

코드로 확인해보자. 

먼저 컴포넌트 스캔을 이용해서 구현할 AppConfig가 필요하다. 

다음과 같이 core의 하위에 이름을 AutoAppConfig로 만들어준다.

 

 

AutoAppConfig

package hello.core;


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan( //@Component annotation이 붙은 클래스를 자동으로 스캔해서 스프링 빈으로 등록해줌,
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
        //@Component 가 붙은 클래스 중 자동스캔에서 @Configuration이 붙은 것은 제외할 것(AppConfig->@Configuration(얘도 내부에 @Component가 있음) 때문에 작성된부분)
)
public class AutoAppConfig {




}

AppConfig와 마찬가지로 @Configuration이라고 설정정보를 담았다는 의미의 annotation을 포함한다.

중요한 점은 내부에 @Bean으로 등록되지 않았다는 점과

@ComponentScan annotation을 부착했다는 점이다.

이는 @Component가 부착된 모든 클래스를 스캔하여, 스프링 빈으로 등록하겠다는 의미이다.

(그 아래에 exclude라고 적힌 부분은 주석을 참고) AppConfig를 고려하지 않기 위함이며, 실제로는 붙이지않음 

 

 

이제 기존 AppConfig에 존재하는 4가지의 클래스에 @Component라는 annotation을 추가해준다.

MemoryMemberRepository

RateDiscountPolicy

MemberServiceImpl

OrderServiceImpl

 

자세히 보면, 

MemberServiceImpl과 OrderServiceImpl은 의존관계를 가진다.

이는 그들이 생성자를 보면, 매개변수에 의존이 있는 모습을 볼 수 있는데, 생성자에 @Autowired를 부착하면, 자동으로 의존관계가 성립된다.

 

<끝>

 

 

 

실제로, appConfig와 동일하게 돌아가는지 확인하기 위해 다음과 같이 테스트 코드를 작성해준다.

 

scan이라는 패키지 하위에 AutoAppConfigTest를 생성한다.

 

다음과 같이 AutoAppConfig로 스프링 컨테이너를 생성하여,  간단한 테스트 코드를 실행해보면, 똑같이 실행됨을 알 수 있다.

package hello.core.scan;

import hello.core.AutoAppConfig;
import hello.core.member.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.assertj.core.api.Assertions.assertThat;

public class AutoAppConfigTest {


    @Test
    void basicScan(){

        //autoAppConfig 사용
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);


        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberService.class);

    }
}

 

 

 

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

 

1. @ComponentScan

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

이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다.

 

2. @Autowired의존관계 자동 주입

생성자에 @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다. 

이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.

getBean(MemberRepository.class) 와 동일하다고 이해하면 된다.

 

파라미터가 여러개로 의존관계가 여러개여도 잘 작동한다.(orderServiceImpl처럼 2개인경우도 잘 작동) 

 

 

 

 

탐색 위치

 

모든 자바 클래스를 하나하나 컴포넌트 스캔하면 시간이 오래걸리므로, 스캔 위치를 지정할 수 있다.

@ComponentScan(
          basePackages = "hello.core",
}

basePackages : 탐색할 패키지의 시작 위치를 지정한다. 이 패키지를 포함해서 하위 패키지를 모두 탐색한다.

여러개를 적는 것도 가능하다.

지정하지 않으면, @ComponentScan이 붙은 클래스의 패키지가 시작위치가 된다.

 

따라서, 패키지 위치를 따로 지정하지 않고, 설정 정보 클래스(AppConfig)의 위치를 프로젝트 최 상단에 두는 것을 권장한다.

더보기

이런ㄹ 경우 com.hello를 포함한 하위가 모두 컴포넌트 스캔의 대상이 된다.

프로젝트의 메인 설정 정보는 프로젝트를 대표하기 때문에 시작 루트 위치에 두는 것이 좋다.

 

* 참고 : 스프링 부트의 대표 시작 정보인 @SpringBootApplicaiton를 프로젝트 시작 루트 위치에 두는 것이 관례(이 설정안에도 @ComponentScan 이 들어있음) 

 

 

 

컴포넌트 스캔 기본 대상

컴포넌트 스캔은 @Component 뿐만 아니라 다음과 내용도 추가로 대상에 포함한다. 

  • @Component : 컴포넌트 스캔에서 사용
  • @Controlller : 스프링 MVC 컨트롤러에서 사용
  • @Service : 스프링 비즈니스 로직에서 사용
  • @Repository : 스프링 데이터 접근 계층에서 사용 
  • @Configuration : 스프링 설정 정보에서 사용

이들은 모두 소스 코드를 열어보면 @Component를 포함한다. 

(annotation에는 상속관계는 없다! annotation이 특정 annotation을 가지고 있는 것은 자바가 지원하는 기능이 아니며, 스프링에서 지원하는 기능이다.) 

 

또한, 컴포넌트 스캔의 용도 뿐 아니라 부가기능을 수행한다.

  • @Controller : 스프링 MVC 컨트롤러로 인식
  • @Repository : 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해준다.
  • @Configuration : 앞서 보았듯이 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가있겠구나 라고 비즈니스 계층을 인식하는데 도움이 된다.처리를 한다.
  • @Service : 사실 @Service 는 특별한 처리를 하지 않는다. 대신 개발자들이 핵심 비즈니스 로직이 여기에 있겠군 하며, 비즈니스 계층을 개발자가 인식하는데 도움을 준다.

(나중에 나올 것 그냥 대충) 

 

또한, useDefaultfilters옵션은 기본적으로 on상태인데, 옵션을 끄면 기본 스캔 대상에서 제외 시킬 수도 있다. 

 

728x90