목차
@ComponentScan
@ComponentScan 애노테이션은 spring 3.1부터 도입됐으며 설정된 시작 지점부터 컴포넌트 클래스를 scanning하여 빈으로 등록해주는 역할을 한다.
컴포넌트 클래스는 다음 애노테이션이 붙은 클래스를 의미한다.
- @Component
- @Repository
- @Service
- @Controller
- @Configuration
@ComponentScan의 가장 중요한 두 가지 속성은 component를 scan할 시작 지점을 설정하는 속성과 scan한 component 중 빈으로 등록하지 않을 클래스를 제외하는 필터 속성이다.
component-scan은 기본적으로 @Component 어노테이션을 빈 등록 대상으로 포함한다. 그렇다면 @Controller 나 @Service는 어떻게 인식하는 걸까? 그 이유는 @Controller나 @Service가 @Component를 포함하고 있기 때문이다.
component-scan 사용방법
component-scan 을 사용하는 방법은
xml 파일에 설정하는 방법, 과 자바파일안에서 설정하는 방법이 있다.
1. xml 파일에 설정
<context:component-scan base-package="com.rcod.lifelog"/>
다음과 같이 xml 파일에 설정하고, base package를 적어주면 base package 기준으로 클래스들을 스캔하여 빈으로 등록한다.
base package에 여러개의 패키지를 쓸 수 있다.
<context:component-scan base-package="com.rcod.lifelog, com.rcod.example"/>
위와 같이 설정하면, base pacakage 하위의 @Controller, @Service @Repository, @Component 클래스가 모두 빈으로 등록되므로, 특정한 객체만 빈으로 등록하여 사용하고 싶다면 include-filter나 exclude-filter를 통해 설정할 수 있다.
- exclude-filter
<context:component-scan base-package="com.rcod.lifelog">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
@Controller 를 제외하고 싶다면 위와 같이 exclude-filter를 사용하여
org.springframework.stereotype.Controller를 명시해준다.
- include-filter
<context:component-scan base-package="com.rcod.lifelog" use-default="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
use-default="false"는 기본 어노테이션 @Controller, @Component등을 스캔하지 않는다는 것이다. 기본 어노테이션을 스캔하지 않는다고 설정하고, include-filter를 통해서 위와 같이 특정 어노테이션만 스캔할 수 있다.
2. 자바 파일안에서 설정
@Configuration
@ComponentScan(basePackages = "com.rcod.lifelog")
public class ApplicationConfig {
}
@Configuration 은 이 클래스가 xml을 대체하는 설정 파일임을 알려준다. 해당 클래스를 설정 파일로 설정하고 @ComponentScan을 통하여 basePackages를 설정해준다.
- 위와 같이 component-scan을 사용하는 두 가지 방법이 있다. 만약 component-scan을 사용하지 않으면, 빈으로 설정할 클래스들을 우리가 직접 xml 파일에 일일이 등록해 주어야 한다.
<bean id="mssqlDAO" class="com.test.spr.MssqlDAO"></bean>
<!-- MemberList 객체에 대한 정보 전달 및 의존성 주입 -->
<bean id="member" class="com.test.spr.MemberList">
<!-- 속성의 이름을 지정하여 주입 -->
<property name="dao">
<ref bean="mssqlDAO"/>
</property>
</bean>
MssqlDAO 와 MemberList를 빈으로 등록하고, MemberList에 Mssql을 주입한 것이다. 위와 같이 코드가 매우 길어지고, 일일이 추가하기에 복잡해진다.
component-scan 동작 과정
ConfigurationClassParser 가 Configuration 클래스를 파싱한다.
@Configuration 어노테이션 클래스를 파싱하는 것이다.
⬇
ComponentScan 설정을 파싱한다.
base-package 에 설정한 패키지를 기준으로
ComponentScanAnnotationParser가 스캔하기 위한 설정을 파싱한다.
⬇
base-package 설정을 바탕으로 모든 클래스를 로딩한다.
⬇
ClassLoader가 로딩한 클래스들을 BeanDefinition으로 정의한다.
생성할 빈의 대한 정의를 하는 것이다.
⬇
생성할 빈에 대한 정의를 토대로 빈을 생성한다.
Spring boot에서의 @ConponentScan
이전 Xml Config 방식에서 ComponentScan을 사용하는 방법은 다음과 같았다.
<context:component-scan base-package="com.example.a">
applicationContext를 구성할때 이렇게 명시적으로 내가 읽어들여야하는 component들이 있는 package를 넣어줬다.
하지만 Springboot에서는 Xml Config보다는 Java Config를 사용하고 @기반의 설정을 많이 한다. 아니 이 Component Scan을 하지도 않는데 알아서 잘 된다. 어떻게 된 일일까? 바로 Springboot의 핵심! @SpringBootApplication 에 답이 있다. Springboot Main Class에 있는 @SpringBootApplication를 ctrl을 누르고 눌러서 들어가보자.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
... 생략 ...
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
... 생략 ...
들어가보면 이런식으로 구성이 되어있다. 복잡해 보이지만 쉽게 설명을 하자면 내가 아무런 ComponentScan 관련 설정을 하지 않았다면 바로 이 @SpringBootApplication 가 정의된 곳이 base package가 되는 것이다. 그래서 처음 프로젝트 구조를 만들때 이 Springboot Main Class의 package가 매우 중요하다.
그리고 아래에 나와있는 @AliasFor 부분에 나온 basePackages와 basePackagesClasses도 중요하다. Springboot Main Class의 위치에 구애받지 않고 내가 마음대로 ComponentScan을 할 곳을 정의할때 사용된다.
'Spring' 카테고리의 다른 글
[Spring] PHP 사용 소감 (Spring과 비교) (0) | 2022.05.05 |
---|---|
스프링 vs 스프링 부트 (0) | 2021.03.31 |