본문 바로가기

Spring

컴포넌트 스캔

- 스프링에서 객체를 스프링 컨테이너가 관리하도록 하려면 스프링 컨테이너에 등록되어야 합니다. 

  하지만 이러한 등록을 일일이 하는 것은 번거롭습니다. 

  따라서 스프링에서는 '컴포넌트 스캔'을 통해서 스프링 빈의 자동 등록을 지원합니다. 

 

1) 컴포넌트 스캔이란?

- 컴포넌트 스캔이란 말 그대로 '컴포넌트''스캔'하는 것입니다. 

  스프링에서 스프링 빈으로 등록하고 싶은 클래스를 @Component를 표기하면,

  컴포넌트 스캔을 통해 해당 클래스를 스프링 빈으로 등록합니다.

   이 때, 컴포넌트 스캔을 수행하는 클래스는 @ComponentScan이 붙어야 합니다. 

package hello.core;

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

@Configuration
@ComponentScan(
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class))
public class AutoAppConfig {
 
}

 

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

- 컴포넌트 스캔을 통해 클래스들을 스프링 빈으로 설정해주면,  

  스프링 빈 간의 의존 관계를 주입해줘야 합니다. 

  이 때, 해당 클래스의 생성자에 @Autowired를 붙이면 해당 스프링 빈을 찾아서 주입해줍니다.

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

 

3) 탐색 위치와 기본 스캔 대상

- 컴포넌트 스캔은 특정 위치부터 탐색을 시작하도록 지정할 수 있습니다. 

@ComponentScan(
	basePackages = "hello.core"
}

- 이렇게 탐색의 시작 위치를 지정하면, 이 패키지를 포함해서 하위 패키지만 탐색합니다. 

-> 일반적으로 스프링 부트를 사용하면 스프링 부트의 대표 시작 정보인 @SpringBootApplication

     프로젝트의 시작 위치에 두는 것이 관례이고,

     @SpringBootApplication 안에 @ComponentScan이 들어 있습니다. 

 

 

4) 컴포넌트 스캔 기본 대상

- 컴포넌트 스캔은 @Component 뿐만 아니라 다음 애너테이션들도 추가로 포함합니다.

(1) @Controller: 스프링 MVC 컨트롤러에서 사용 

(2) @Service: 스프링 비즈니스 로직에서 사용

(3) @Repository: 스프링 데이터 접근 계층에서 사용

(4) @Configuration: 스프링 설정 정보에서 사용 

 

 

5) 필터

- 필터를 통해서 컴포넌트 스캔 대상을 추가로 지정하거나, 제외할 대상을 지정할 수 있습니다. 

(1) includeFilters: 컴포넌트 스캔의 대상을 추가로 지정합니다.

(2) excludeFilters: 컴포넌트 스캔에서 제외할 대상을 지정합니다. 

 

컴포넌트 스캔 대상에 추가할 애너테이션

package hello.core.scan.filter;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}

컴포넌트 스캔 대상에서 제외할 애너테이션

package hello.core.scan.filter;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}

컴포넌트 스캔 대상에 추가할 클래스

package hello.core.scan.filter;

@MyIncludeComponent
public class BeanA {
}

컴포넌트 스캔 대상에서 제외할 클래스

package hello.core.scan.filter;

@MyExcludeComponent
public class BeanB {
}

설정 정보와 전체 테스트 코드

package hello.core.scan.filter;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.context.annotation.ComponentScan.Filter;

public class ComponentFilterAppConfigTest {
 @Test
 void filterScan() {
	 ApplicationContext ac = new
	 AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
 	 BeanA beanA = ac.getBean("beanA", BeanA.class);
 	 assertThat(beanA).isNotNull();
 	 Assertions.assertThrows(
 		NoSuchBeanDefinitionException.class,
 		() -> ac.getBean("beanB", BeanB.class));
 	 }
 
 	
    @Configuration
 	@ComponentScan(
 		includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
 		excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
 	)
 	static class ComponentFilterAppConfig {
 	}
}

 

6) 필터 타입 옵션

- 필터 타입에는 5가지 옵션이 있습니다.

(1) ANNOTATION: 기본값, 애노테이션을 인식해서 동작.

     ex) org.example.SomeAnnotation

(2) ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작.

     ex) org.example.SomeClass

(3) ASPECTJ: AspectJ 패턴 사용

     ex) org.example..*Service+

(4) REGEX: 정규 표현식

     ex) org\.example\.Default.*

(5) CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리

    ex) org.example.MyTypeFilter

 

참고

김영한 스프링 핵심 원리 

'Spring' 카테고리의 다른 글

롬복  (0) 2022.08.21
의존관계 자동 주입  (0) 2022.08.21
웹 서버와 WAS  (0) 2022.08.14
스레드 풀  (0) 2022.08.14
싱글톤 컨테이너  (0) 2022.08.13