본문 바로가기
코딩log/Spring Framework

[Spring Framework]ComponentScan과 자동 의존관계 주입

by 벨크 2023. 4. 11.
반응형

  System 규모가 작은 경우에는 Bean 정보를 담고 있는 객체를 직접 구성하면 됩니다. 우리가 여태까지 Java 클래스로 구생했던 appConfig 같은 파일을 만들어서 말이죠. 그리고 이 파일에 직접 의존관계를 주입하면 됩니다.

 

  그런데 System이 커지면 Bean 정보를 등록해 주는 객체도 커지고, 설정 정보도 커지게 됩니다. 설정 정보가 커지고 해당 설정 정보를 수정하는 개발자들이 많아지면 당연히 장애 포인트가 많아지겠죠. 이를 방지하기 위해서 Spring Framework에서는 자동으로 Spring Bean을 등록하는 기능을 제공해 줍니다.

ComponentScan과 자동 의존관계 주입

ComponentScan과 자동 의존관계 주입

 

@ComponentScan

  그렇다면, 어떻게 Spring Framework에서 자동으로 빈 정보를 관리해 줄 수 있을까요? 바로 @ComponentScan이라는 Annotation을 사용하면 됩니다. Bean 정보를 관리할 객체를 생성하고 @ComponentScan을 붙여주면 끝입니다.

 

  Bean으로 등록할 Class위에 @Component라는 Annotation을 붙이면 됩니다. 그럼 스프링이 @ComponentScan이 붙은 클래스를 빌드할 때, @Component가 붙은 클래스를 Bean으로 등록합니다.

 


//자동으로 Bean등록을 해주는 ComponentScan 객체의 기본 작성
@Configuration
@ComponentScan
public class AutoAppConfig {

}

//Bean으로 등록할 객체
@Component
public class Driver {
    private final Car car;
    
    @Autowired
    public Driver(Car car){
        this.car = car;
     }
}

  위의 코드처럼 ComponentScan 클래스에 @ComponentScan을 붙여주고, 등록할 Bean에 @Component를 붙여주면 됩니다. 의존관계 주입이 필요한 경우에는 @Autowired를 붙여주면 자동으로 의존관계주입을 해줍니다.

 

ComponentScan의 시작 위치

 

  모든 자바 클래스를 찾아가며 ComponentScan을 하면 시간이 아주 오래 걸립니다. 그래서 컴포넌트 스캔은 기본적인 시작위치가 있고, 또 시작 위치를 임의로 지정할 수 있습니다. 기본 시작위치는 ComponentScan 클래스가 포함된 package부터 그 하위 package를 모두 스캔합니다.

 

  시작위치를 임의로 지정하는 방법은 두 가지가 있습니다. 패키지로 지정하는 방법과 클래스로 지정하는 방법이 있습니다. 지정은 다음과 같이 Annotation에 속성을 부여하면 됩니다.

@ComponentScan(
    basePackages = "hello.core", //패키지로 지정
    basePackageClasses = AutoAppconfig.class //특정 클래스가 포함된 패키지로 지정
    )

 

Filter

 

  그런 경우는 없어야 하겠지만, 컴포넌트 스캔 대상 클래스 중에 스캔을 예외 하고 싶은 경우도 있습니다. 또 스캔 대상이 아닌데 스캔에 추가하고 싶은 경우도 있습니다. '@Component를 붙이고 안 붙이고 선택하면 되는 거 아니냐?'라고 생각할 수 있습니다. 그런데 @Component가 기본적으로 포함된 Annotation들이 있습니다.

  • @Controller
  • @Service
  • @Repository
  • @Configuration

  위의 Annotation을 사용하는 경우에는 스캔 대상으로 만들고 싶지 않아도 자동으로 스캔 대상이 됩니다. 이런 경우에 컴포넌트 스캔 대상에 추가/제외시키기 위해서 Filter라는 속성을 사용합니다.

@ComponentScan(
    includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class)
        },
    excludeFilters = {
        @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = AppConfig.class),
        @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
        }
    )

 

Component Scan의 우선순위

 

  컴포넌트 스캔이 자동으로 스프링 빈을 등록하다 보면, 수동으로 등록한 같은 이름의 빈과 충돌이 날 수 있습니다. 이럴 경우 수동으로 등록한 빈이 높은 우선순위를 가집니다. 같은 이름의 자동 등록 빈과 수동 등록 빈이 있으면 수동으로 등록한 빈만 스프링 빈에 등록이 됩니다. 스프링 부트에서는 혹시 모를 사고를 대비해 같은 이름의 빈이 등록되면 에러를 내고 있습니다. 자동으로 똑같은 이름의 빈이 등록 된다면 스프링 빌드 시에 오류가 발생합니다.

 

자동 의존관계 주입

 

  자동 의존관계 주입에 대해서는 조금 더 디테일하게 공부를 할 예정입니다. 오늘 포스팅에서는 간단하게 짚고 넘어가겠습니다. @Autowired를 붙이면 스프링 빈에 등록되어 있는 의존관계가 자동으로 등록됩니다. 그럼 어떠한 방식으로 @Autowired를 붙이는지 알아보겠습니다.

 

  1. 생성자 주입(Spring Bean일 경우): Consturctor 선언 위에 @Autowired를 붙입니다. 빈을 등록하면서 생성자가 호출될 때 한 번만 호출됩니다. 따라서 주입된 의존 관계가 불변합니다. 생성자가 하나만 있을 경우 Annotation을 생략 가능합니다.
  2. 수정자 주입/함수 주입: 생성자를 안 쓰고 직접 setter나 기타 함수의 선언 위에 @Autowired를 붙여 의존관계를 주입합니다. 선택적으로 의존관계를 주입할 수 있습니다. @Autowired(required = false)로 세팅하면 의존관계가 필수값이 아니게 됩니다.
  3. 필드 주입(비권장): private 객체를 선언하는 곳에 @Autowired를 붙여 필드에 직접 주입합니다. 테스트가 용이하지 않은 등의 이유로 권장하지 않는 방식입니다.
반응형

댓글