안녕하세요!

열심히 스프링 Bean들의 설정을 구성하느라 고생 많으셨죠? 오늘은 조금 더 간편한 방법을 배워보려 합니다.

만약에 프로젝트가 마구 커져서 Bean이 엄청나게 많아지게 되면 AppConfig를 작성하기가 너무 막막하겠죠? 이를 위해서 자동으로 Bean들을 찾아서 구성해 주는 기능인 Component Scan을 한번 사용해 봅시다!

👉이전 글 보러가기


@Component 지정해 주기

찾아달라고 얘기하기 전에 우선 나를 찾아달라는 표시를 우리의 클래스들에게 데코레이터로 지정해 줄 수 있습니다.

즉 이 데코레이터가 붙어야지만 스프링에서 찾아서 자동으로 등록해 준다는 것이겠죠?

(배우자를 찾는 감동 실화 눈물콧물 다짜는 스토리 꼭 보세요! (ㅎㅎ..ㅈㅅ!!))

우리가 만들었던 구현 클래스들에게 한번 슬쩍 넣어볼까요?

이렇게 MemoryMemberRepository, FixDiscountPolicy, RateDiscountPolicy, MemberServiceImpl, OrderServiceImpl 위에 데코레이터를 추가해줍시다!

좋습니다! 이제 자동으로 스캔할 준비는 완료되었습니다!


Component Scan 클래스 만들기

이제 우리가 찾아달라고 설정했던 클래스들을 자동으로 찾아주는 설정 클래스를 만들게요! 이제 이전에 만든 AppConfig는 쓰지 않겠습니다.

(샤라랄라~)

새로 클래스를 만들어봅시다. 경로는 src/main/java/com/naver/shopping에 만들어주고 자동으로 해주니까 이름은 AutoAppConfig로 할게요.

이 친구는 우리의 새 설정 파일이기 때문에 @Configuration 데코레이션을 추가해 줍니다. 그리고 @ComponentScan을 넣어주면 얘는 앞으로 우리가 설정한 녀석들을 자동으로 포함하는 설정파일이 됩니다. 한번 해볼까요?

// AutoAppConfig.java
 
package com.naver.shopping;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@ComponentScan
public class AutoAppConfig { }

이게… 끝..? 네 끝입니다. 하지만 지금 당장은 조금의 문제가 있기 때문에 조금 수정을 진행해보려 합니다. 그전에 우선 @ComponentScan이 자동으로 찾는 데코레이터의 목록을 알아봅시다.

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

우선 저희가 익숙한 건 @Component 그리고 @Configuration이네요.

지금 문제점은 바로 저희가 이미 수동으로 짜놨던 AppConfig가 @Configuration 데코레이션을 사용하기 때문에 AppConfig에서 등록한 Bean들도 AutoAppConfig에 등록이 되면서 또 @Component를 추가한 것 때문에 같은 Bean들이 중복해서 등록되게 되겠죠? 그럼 저희는 AutoAppConfig에 AppConfig의 정보까지 등록되는 것을 막아야 합니다. 물론 AppConfig를 지우면 되긴 하겠지만 아까우니까! 살리면서 자동등록을 막아봅시다.


Component Scan 필터링

아무리 자동으로 불러온다고 이것저것 막 불러오면 이렇게 문제점을 초래할 수 있겠죠? 자동으로 불러올 것들 또는 불러오고 싶지 않은 것들을 따로 필터링해서 불러오는 방법에 대해 알려드리겠습니다.

1. 얘는 빼고 불러올래요

지금 저희가 딱 필요한 경우입니다. AppConfig만 빼고 불러오고 싶다면 excludeFilters를 @ComponentScan에 설정해 주면 됩니다. 예시를 바로 보시죠!

package com.naver.shopping;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
 
@Configuration
@ComponentScan(
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig { }

@ComponentScan 안에 excludeFilters 설정을 할 수 있는데, @ComponentScan하위의 Filter라는 기능을 써서 필터링할 기준을 제시할 수 있습니다.

type으로 필터링 할 타입을 설정하고, classes로 해당 타입의 필터링 할 기준을 넣어주면 됩니다.

저희는 저 코드상에서 @Configuration 어노테이션을 가진 클래스들은 자동 스캔에서 제외해 주도록 작성했습니다. 이렇게 되면 AppConfig는 @Configuration을 가지고 있기 때문에 AutoAppConfig의 스캔 범위에서 벗어나게 되었습니다!

2. 얘는 꼭 껴주세요

스캔 검색 범위가 아니지만 그래도 얘가 들어간 애들은 꼭 찾아줬으면 할 때도 있습니다. 그럴 때는 includeFilters를 사용하시면 됩니다. 하는 방식은 excludeFilters를 할 때와 정말 비슷합니다. 보여드리겠습니다!

package com.naver.shopping;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Service;
 
@Configuration
@ComponentScan(
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class),
        includeFilters = @Filter(type = FilterType.ANNOTATION, classes = Service.class)
)
public class AutoAppConfig { }

마지막으로 저 Filter의 타입은 뭐가 오는지 알고 싶으시죠? 아래를 참고해 주세요.

  • ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.
    ex) org.example.SomeAnnotation
  • ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
    ex) org.example.SomeClass
  • ASPECTJ: AspectJ 패턴 사용
    ex) org.example..*Service+
  • REGEX: 정규 표현식
    ex) org. example. Default.*
  • CUSTOM: TypeFilter이라는 인터페이스를 구현해서 처리
    ex) org.example.MyTypeFilter

좋습니다! 저희는 지금 여기서 예시를 위해 includeFilters를 추가한 것이기 때문에 includeFilters는 지우고 넘어가도록 할게요~


Component Scan 탐색 범위 지정

Component Scan은 기본적으로 어느 경로부터 해서 컴포넌트들을 찾을까요? 바로 Component Scan이 달린 저희의 AutoAppConfig의 맨 위에서 답을 찾을 수 있습니다.

// AutoAppConfig.java
 
package com.naver.shopping;
...

바로 AutoAppConfig의 패키지로부터 스캔을 하게 됩니다. 그럼 저희가 직접 지정할 수도 있겠죠? 한 개도 가능하고 여러 개 또한 가능합니다.

예를 들어 저희 shopping의 member와 order의 하위 클래스중에서만 스캔하고 싶다면 아래와 같이 설정하면 됩니다.

@Configuration
@ComponentScan(
        basePackages = {"com.naver.shopping.member", "com.naver.shopping.order"},
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig { }

하나만 지정한다면 중괄호는 빼고 문자열로 하나만 넣으시면 됩니다.

하지만! 주로 최상단부터 검색하는 방법을 주로 쓰고, 저희도 그럴 예정이라 basePackages설정은 빼고 진행하겠습니다.


마치며

Component를 지정하는 것과 Component Scan을 만드는 것을 진행해 보았습니다.

오늘은 분량도 적고 아주 간단했는데요, 다음 시간에는 Autowired라는 클래스 의존관계를 자동으로 주입하는 방법도 배워보겠습니다. 이 작업까지 완벽히 하셔야 저희는 완벽하게 자동으로 구성되는 Config파일을 가질 수 있게 되는 거여서 다음 글까지 꼭 봐주시면 감사하겠습니다.

오늘 작업한 수정사항은 아래 커밋에서 확인하실 순! 있지만 여러 가지 옵션들을 적용해본건 나와있지 않으니 본문 꼭 참고해 주세요!

https://github.com/KIMB0B/blog_spring/commit/d45ddc700f2d2fd942e20881a1ec4dbe35a23032

👉다음 글 보러가기