[Spring] context:component-scan에 관하여
기술/Java & Spring

[Spring] context:component-scan에 관하여

반응형

✏️개요

  이번에 작성할 글의 주제는 context:component-scan(이하 component-scan) 필자가 이것을 처음 접한 것은 취업 준비를 위해 Spring Framework를 독학하고 있던 시절, XML을 이용한 bean 등록 방법 이후에 어노테이션을 이용한 bean 등록에서 알게 되었고, component-scan이 제공하는 편한 기능을 단순히 감탄하며 사용하기만 해왔다.

 

  현재 실무에서 진행되는 프로젝트에 기능 추가를 무사히 마친 뒤, 시간이 남게 되어 Java의 개념에 집중했던 이전과는 달리 스프링에 대한 기초 지식을 단단히 하고자 스프링 설정 파일을 열었고 그곳에서 component-scan을 만날 수 있었다. 그곳에 있던 것은 역시 독학하며 사용한 기본적인 형태의 component-scan이 아닌, 다른 모습을 하고 있는 component-scan이 있었고 이를 이해하기 위해 많은 자료를 뒤지게 되면서 알게 된 사실들을 이 글에 남기고자 마음먹게 되었다.  

 

❗ 본 게시글은 필자 개인적인 의견이므로 틀린 부분이 있을 수 있습니다. 댓글을 통해 지적해주시면 감사하겠습니다.

✏️Component-scan이란?

  개요 부분에서 간략하게 언급하였지만 component-scan이란, 우리가 스프링에서 위의 이미지와 같은 어노테이션을 클래스에 함께 선언하게 되면 스프링이 자동으로 해당 어노테이션이 붙은 클래스들을 스캔하여 bean으로서 생성해주는 것을 가능하게 해주는 설정이다. 이는 기존의 XML에 장황하게 bean을 생성하기 위한 설정을 작성하는 과정을 드라마틱하게 줄여주는 방법이라 할 수 있다. 

 

<context:component-scan base-package="패키지명"/> 

  component-scan은 context xmlns(이하 xml namespace)에 정의되어 있는 접두어를 통해 사용 가능한데, 이때 위에서 언급하였듯이 어노테이션이 붙은 클래스들을 스캔하여 bean으로 만들기 위해서 base-package="패키 지명"을 통해 스캔 범위를 정할 수 있다. 

이와 같은 component-scan을 Java 내에서 어노테이션을 이용해 설정하는 방법 또한 존재하지만, 필자는 현재 있는 실무에서 xml을 이용해 설정하기 때문에 그에 관해서만 알아보고자 한다.

✏️Component-scan의 Customize

  여기까지의 내용이 필자가 스프링을 독학하면서 배우고, 사용했던 가장 기본적인 component-scan에 대한 설명이었다. 지금부터는 현재 실무에서 사용되고 있는 필터를 이용한 스캐닝의 커스터마이징에 대해서 살펴보고자 한다. 

 

  필터를 이용한 스캐닝의 커스터마이징, 말이 뭔가 이상한데 쉽게 말하면 component-scan의 스캔을 바꾸는 방법이라는 소리다. 이 말인즉슨 지금까지 이야기한 component-scan에 대한 이야기는 스프링의 기본 설정이라는 것이다. 

 

  component-scan을 커스터마이징 할 때 사용되는 것은 마찬가지로 context접두어를 이용하는 component-scan의 서브 엘리먼트인 두 가지의 방법이 있다. 

  • context:include-filter : 단어 그대로 필터를 통해 포함시키고자 하는 대상.
  • context:exclude-filter : 단어 그대로 필터를 통해 제외시키고자 하는 대상.

  이 두 가지는 모두 type, expression 속성을 갖는데, 이때 사용되는 값들은 아래와 같다.

Filter Example Expression  Description
annotation org.example.SomeAnnotation 타겟 컴포넌트의 타입 레벨에 존재하는 어노테이션을 스캔한다.
assignable org.example.SomeClass 지정한 타입과 할당(extends/implements)할 수 있는 클래스들을 스캔한다.
aspectj org.example..*Service+ aspectj의 표현식과 매치되는 컴포넌트들을 스캔한다.
regex org\.example\.Default.* 클래스 이름이 정규 표현식과 매치되는 컴포넌트들을 스캔한다.

  위의 필터와 함께 component-scan에 사용되는 중요한 속성은 use-default-filters이다. 값은 true와 false를 가질 수 있으며 기본값은 true로 @Component, @Controller, @Repository, @Service와 같은 기본 컴포넌트를 스캔한다는 의미이다. 반대로 false는 기본 컴포넌트를 스캔하지 않는다는 것이다.

 

  여기까지가 component-scan을 커스터마이징 하기 위해 사용되는 요소들이다. 마지막으로 현재 회사에서 사용되고 있는 형식을 간단하게 분석하고 글을 마치겠다.

 

<context:component-scan base-package="최상위 패키지명" use-default-filters="false">
  <context:include-filter type="aspectj" expression="하위 패키지명" />
  <context:include-filter type="aspectj" expression="하위 패키지명" />
	...
</context:component-scan>
  • base-package는 최상위 패키지명을 사용하고, use-default-filters="false"로 기본 컴포넌트들은 스캔하지 않는다.
  • context:include-filter의 type은 aspectj, expression에는 aspectj 표현식을 이용해 하위 패키 지명을 작성해 하위 패키지에 속하는 모든 클래스를 스캔한다. 
  • 기능별로 분리되어 있는 여러 하위 패키지명을 스캔하여 bean을 생성한다.
회사에서 사용되는 component-scan은 위와 같은 방식으로 root context에서는 Controller들을 스캔하고, servlet context에서는 Service들을 스캔하고 있다. 

  추가적으로 처음에는 use-default-filters의 값을 false로 주면 기본 컴포넌트들의 어노테이션을 스캔하지 않는다고 해서 expression에 해당하는 클래스들이 bean으로 생성될 때 어떠한 어노테이션과 같은 bean으로 생성되는지 의문이었는데, 기본적으로 기본 컴포넌트 어노테이션들의 최상위 어노테이션인 @Component로 스캔된 것과 같은 bean으로 생성된다는 것을 어떤 글에서 본 것 같다. 

이 부분은 확실하지 않다.

✏️마치며

여기까지가 현재 실무에서 사용되고 있는 component-scan의 형식이다. 위에서 component-scan이 2개로 분리되어 있다고 했는데, 이에 대해선 다음 글에 작성하고자 한다. 

반응형