컴포넌트 스캔

컴공생의 코딩 일기·2023년 1월 4일
0

스프링

목록 보기
6/16
post-thumbnail

컴포넌트 스캔

컴포넌트 스캔은 스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능이다. 설정 클래스에 빈으로 등록하지 않아도 클래스를 빈으로 등록해주는 기능이다. 설정 클래스에 빈으로 등록하지 않아도 원하는 클래스를 빈으로 등록할 수 있으므로 컴포넌트 스캔 기능을 사용하면 설정 코드가 크게 줄어든다.

@Component 어노테이션으로 스캔 대상 지정

스프링이 검색해서 빈으로 등록할 수 있으려면 클래스에 @Component 어노테이션을 붙여야 한다. @Component 어노테이션은 해당 클래스를 스캔 대상으로 지정한다.

@Component
public class MemberDao{ ... }
  • 기본적으로 @Component에 아무 속성을 지정하지 않을 경우 클래스 이름에 첫 글자를 소문자로 바꿔 빈 이름으로 등록되게 된다.
    • 예) MemberDao -> memberDao
  • 만약 클래스를 빈으로 등록할 때 별도의 이름으로 지정해서 빈으로 등록하고 싶을 경우 아래와 같이 설정해 주면 된다.
@Component("member")
public class MemberDao{ ... }

@Component 어노테이션으로 스캔 설정

@Component 어노테이션을 붙인 클래스를 스캔해서 빈으로 등록하기 위해서는 설정 클래스에 @ComponentScan 어노테이션을 설정해 줘야 한다.

// 빈으로 등록하기 위한 클래스
// MemberDao가 spring 이름으로 된 패키지에 있다고 가정
@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppCtx{
// ... 생략
}

basePackages 속성에 빈에 등록할 패키지를 지정할 경우 해당 패키지와 그 하위 패키지에 속한 클래스를 스캔 대상으로 지정하고 @Component 어노테이션이 지정된 클래스를 빈을 등록한다.

스캔 대상에서 제외하거나 포함하기

excludeFilters 속성을 사용하면 빈으로 등록하기 위해 스캔을 할 경우 특정 대상을 자동 등록 대상에서 제외 시킬 수 있다.

@Configuration
@ComponentScan(basePackages = {"spring"}, 
    excludeFilters = @Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao"))
public class AppCtxWithExclude{
    @Bean
    public MemberDao memberDao(){  
    }
}
  • @Filter 어노테이션 속성

    • type : 제외 대상을 지정하기 위한 type을 지정
      • FilterType.REGEX : 정규식 표현
      • FilterType.ASPECTJ : AspectJ식 표현
      • FilterType.ANNOTATION : 어노테이션 표현
      • FilterType.ASSIGNABLE_TYPE : 특정 타입이나 그 하위 타입을 지정
    • pattern : FilterType을 적용할 값
      • pattren 속성은 String[] 타입이므로 배열을 이용해서 패턴을 한 개 이상 지정 할 수 있다.
excludeFilters = @Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao") 
    // 정규식 표현 spring으로 시작하고 Dao로 끝나는 클래스를 스캔 대상에서 제외
excludeFilters = @Filter(type = FilterType.ASPECTJ, pattern = "spring.*Dao")  
    // AspectJ 표현 spring으로 시작하고 Dao로 끝나는 클래스를 스캔 대상에서 제외
excludeFilters = @Filter(type=FilterTYPE.ASSIGNABLE_TYPE, classes=MemberDao.class)
   // MemberDao를 스캔 대상에서 제외

특정 어노테이션을 스캔 대상에서 제외하고 싶다면 예를 들어 @NoProduct나 @ManualBean 어노테이션을 붙인 클래스는 컴포넌트 스캔 대상에서 제외할 경우

@Retention(RUNTIME)
@Target(TYPE)
public @interface NoProduct{}

@Retention(RUNTIME)
@Target(TYPE)
public @interface ManualBean{}
@Configuration
@ComponentScan(basePackages={"spring","spring2"},
	excludeFilters=@Filter(type=FilterTYPE.ANNOTATION, classes={NoProduct.class,ManualBean.class}))
public class AppCtxWithExclude{...}excludeFilters=@Filter(type=FilterTYPE.ANNOTATION, classes={NoProduct.class,ManualBean.class}))
@ManualBean
@Component
public class MemberDao{...}

@ManualBean 이 붙은 어노테이션을 스캔 대상에서 제외된다.

만약 설정할 필터가 두 개 이상이면 @ComponentScan의 excludeFilters 속성에 배열을 사용해서 @Filter 목록을 전달하면 된다.

@Configuration
@ComponentScan(basePackages={"spring"},
	excludeFilters={
    	@Filter(type=FilterTYPE.REGEX, classes=MemberDao.class, pattern="spring2\\..*"),
    	@Filter(type=FilterTYPE.REGEX, classes=MemberDao.class, classees=ManualBean.class)
    })
public class AppCtxWithExclude{...}

기본 스캔 대상

@Component 어노테이션을 붙인 클래스만 컴포넌트 스캔 대상에 포함되는 것이 아니다. 아래 어노테이션을 붙인 클래스들은 모두 컴포넌트 스캔 대상이 된다.

  • @Component
  • @Controller
  • @Service
  • @Repository
  • @Aspect
  • @Configuration

이 어노테이션들은 @Component와 같은 기능을 수행한다. 이 어노테이션들은 특정 클래스에 동작 방식을 구별할 수 있게 이름으로 분리한 것 뿐이다.

컴포넌트 스캔에 따른 충돌 처리

컴포넌트 스캔 기능을 사용해서 자동으로 빈 등록할 때에는 충돌에 주의해야 한다. 크게 빈 이름 충돌과 수동 등록에 따른 충돌이 발생할 수 도 있다.

1. 빈 이름 충돌

spring 패키지와 spring2 패키지에 MemberRegisterService 클래스가 존재하고 두 클래스 모두 @Conponent 어노테이션을 붙였다고 하자. 이 상태에서 다음 @ComponentScan 어노테이션을 사용하면 익셉션 오류가 발생한다. 두 클래스에 같은 빈 이름을 지정하게 될 경우 타입이 일치하지 않는 빈 이름과 충돌이 나기 때문이다. 같은 빈 이름을 사용할 경우 둥 중 하나에 명시적으로 빈 이름을 지정해서 이름 충돌을 피해야 한다.

2. 수동 등록한 빈과 충돌

만약 스캔할 때 사용하는 빈 이름과 수동 등록한 빈 이름이 같은 경우 수동 등록한 빈이 우선이기 때문에 수동 등록한 빈만 존재하게 된다.

profile
더 좋은 개발자가 되기위한 과정

0개의 댓글