[Spring] 컴포넌트 스캔

2022. 9. 4. 16:52Spring

728x90
반응형
SMALL

@Component 애노테이션

수동으로 설정 클래스에 빈 객체를 등록하지 않고, 자동으로 등록하려면 @Component 애노테이션을 붙여야 한다.

@Component 애노테이션을 클래스에 붙이면 해당 클래스는 스캔 대상이 된다.

@Component
public class ChangePasswordService {
	...
}

이 때 @Component 애노테이션의 속성값을 지정하지 않았으므로 이 클래스 타입의 빈 이름은 클래스 이름의 첫 글자를 소문자로 바꾼 changePasswordService 가 된다.

따라서 이 빈 객체를 사용할 경우 getBean을 사용할 때 타입만으로 지정해도 되고, 이름을 명시하고 싶다면 위의 이름을 사용하면 된다.

 

@Component("listPrinter")
public class MemberListPrinter {
	...
}

만일 위 코드처럼 @Component 애노테이션의 속성값을 지정하면 getBean을 사용할 때 빈 이름으로 해당 속성값을 사용하면 된다.

 

아래는 getBean의 사용예시이다.

MemberListPrinter listPrinter = ctx.getBean("listPrinter", MemberListPrinter.class);
ChangePasswordService changePwdSvc = ctx.getBean(ChangePasswordService.class);

@ComponentScan 애노테이션

@Component 애노테이션을 붙인 클래스를 스캔해서 스프링 빈으로 등록하려면 설정 클래스에 @ComponentScan 애노테이션을 적용해야 한다.

@Configuration //스프링 설정 클래스
@ComponentScan(basePackages= {"spring"})
public class AppCtx {
	...
}

위 코드에서 basePackages 속성값은 {"spring"}이다.

이는 spring 패키지와 그 하위 패키지에 속한 클래스를 스캔 대상으로 설정한다는 뜻이다.

스캔 대상에 해당하는 클래스 중 @Component 애노테이션이 붙은 클래스의 객체를 생성해서 빈으로 등록한다.


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

excludeFilters 속성을 사용하면 스캔할 때 특정 대상을 자동 등록 대상에서 제외할 수 있다.

@ComponentScan(basePackages= {"spring"},
	excludeFilters=@Filter(type=FilterType.REGEX, pattern="spring//..*Dao"))
public class AppCtx {
	...
}

위 코드에서 excludeFilters 의 속성값으로 @Filter 애노테이션을 사용하고 있다.

@Filter 애노테이션의 type 속성값으로 Filter.REGEX를 주었는데 이는 정규표현식을 사용해서 제외 대상을 지정한다.

위 코드를 예로 들면 "spring." 으로 시작하고 "Dao" 로 끝나는 클래스를 컴포넌트 스캔 대상에서 제외한다.

(정규표현식말고 AspectJ 패턴을 사용하는 방법도 있다. 단, 의존 대상에 aspectjweaver 모듈을 추가해야 한다.)

 

특정 애노테이션을 붙인 클래스를 컴포넌트 스캔 대상에서 제외하려면 다음과 같이 excludeFilters 속성을 설정하면 된다.

@Configuration //스프링 설정 클래스
@ComponentScan(basePackages= {"spring"},
	excludeFilters=@Filter(type=FilterType.ANNOTATION,
    			     classes={NoProduct.class, ManualBean.class}))
public class AppCtx {
	...
}

위 코드에서는 @NoProduct 애노테이션과 ManualBean 애노테이션을 붙인 클래스가 제외 대상이 된다.

 

특정 타입이나 그 하위 타입을 컴포넌트 대상에서 제외하려면 ASSIGNABLE_TYPE을 FilterType으로 사용하면 된다.

@Configuration //스프링 설정 클래스
@ComponentScan(basePackages= {"spring"},
	excludeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, classes=MemberDao.class))
public class AppCtx {
	...
}

 

설정할 필터가 두 개 이상이면 excludeFitlers 속성에 배열을 사용해 여러 개의 @Filter 애노테이션을 사용할 수 있다.

excludeFilters={
    @Filter(...),
    @Filter(...)
}

 

이외에 컴포넌트 스캔 대상에 포함되는 애노테이션은 다음과 같다.

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

(@Aspect 애노테이션을 제외한 나머지 애노테이션은 @Component 애노테이션에 대한 특수 애노테이션이다.)


충돌 처리

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

 

spring 패키지와 spring2 패키지에 같은 이름의 클래스가 존재하고 두 클래스 모두 @Component 애노테이션이

붙어있다고 가정하자.

@Configuration //스프링 설정 클래스
@ComponentScan(basePackages= {"spring", "spring2"})
public class AppCtx {
	...
}

위의 AppCtx 설정 클래스는 spring2에 있는 같은 이름의 클래스를 빈으로 등록할 때 에러를 일으킬 것이다.

따라서 서로 다른 타입인데 같은 빈 이름을 사용하는 경우에는 둘 중 하나에 명시적으로 빈 이름을 지정해서 이름 충돌을 피해야 한다.

 

 

MemberDao 클래스에 @Component 애노테이션을 붙이고,

설정 클래스에 같은 타입의 memberDao 라는 이름의 빈을 등록하면 어떨까?

 

이럴 경우 설정 클래스에 수동으로 등록한 빈이 우선되므로 MemberDao 타입 빈은 한 개만 존재한다.

 

두 개의 빈을 생성하고 싶으면 하나의 빈 이름을 변경하고, 타입이 같으므로 @Qualifier 애노테이션을 사용해야 한다.

728x90
반응형
LIST

'Spring' 카테고리의 다른 글

[Spring] AOP 프로그래밍  (0) 2022.09.05
[Spring] 빈 라이프사이클과 범위  (0) 2022.09.04
[Spring] 자동 주입  (0) 2022.08.31