스프링

스프링 기초- 컴포넌트 스캔

ho코딩 2024. 2. 15. 20:14

저번 시간까지는 스프링 빈을 등록할 경우 @Bean 어노테이션을 통해서 설정 정보에 직접 등록을 했는데요. 

 

실무에서는 등록해야할 @Bean이 수십, 수백개가 되면서 굉장히 귀찮아집니다. (누락문제도 추가)

 

그래서 설정 정보 없이도 자동으로 스프링 빈을 등록하는 '컴포넌트 스캔'이라는 기능이 있는데요. 

 

 

컴포넌트 스캔 기능을 확인하기 위해 기존의 AppConfig를 내버려두고 , AutoAppConfig 파일을 새로 만들었습니다. 

(excludeFilters는 이전에 @Configuration이 붙은 AppConfig도 스캔되는 것을 방지하기 위해, 추가한 코드입니다.)

 

이 코드를 보면 설정 정보 파일인데도 @Bean 어노테이션이 하나도 없습니다. 

 

@ComponentScan 어노테이션이 붙으면 @Configuration이 붙은 설정 정보도 자동으로 등록이 되는데

그 이유는 @ComponentScan 어노테이션을 자세히 들여다 보면,

이 역시도 @Component 어노테이션이 내장되어있기 때문입니다. 

 

그리고 이제 각 클래스가 컴포넌트 스캔의 대상이 되도록 @Component 어노테이션을 붙여줍니다. 

 

이전에는 AppConfig에서 @Bean을 통해 설정 정보도 작성했고, 의존관계도 명시했는데 

AutoAppConfig는 그런 설정 정보가 없으므로 의존관계 주입도 클래스 안에서 해결해야 합니다. 

 

이때 @Autowired 어노테이션이 사용됩니다. 

-@Autowired는 생성자에서 여러 의존관계를 한 번에 주입받을 수 있습니다. (뒤에 더 자세히 설명)

 

 

결과적으로, @ComponentScan을 통해서 @Component가 붙은 모든 클래스를 스프링 빈으로 등록합니다. 

-이때 이름은 클래스명을 그대로 사용하지만 맨 앞자리는 소문자로 유지됩니다. 

-@Component("memberService2")와 같은 식으로 어노테이션을 붙이면 이름을 직접 지정도 가능합니다. 

 

 

@Autowired


@Autowired는 의존관계를 자동으로 주입해주는 어노테이션 입니다. 

그림과 같이 MemberServiceImpl 클래스의 MemberServiceImpl 생성자 부분에 @Autowired를 붙여주면 

스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입해줍니다. 

이는 getBean(MemberRepository.class)와 동일한 방식입니다. 

 

 

이와 같이, 생성자에 파라미터가 복수여도 다 찾아서 주입시켜줍니다. 

 

참고로, 위 @Component 부분을 보면 

이렇게 되어 있는데, 이걸 보고 스프링은 파라미터의 타입을 보고 

 

"아 MemberRepository의 구현체는 MemoryMemberRepository이구나"하고 

 

생성자에서 memberRepository를 불러오면 스프링 빈에서 memoryMemberRepository를 꺼내오는 겁니다. 

 

 

컴포넌트 스캔 기본 대상

 

컴포넌트 스캔은 @Component 뿐만 아니라 다른 경우에도 스캔 대상으로 포함합니다. 

1.@Component : 컴포넌트 스캔에 당연히 포함

2.@Controller : 스프링 MVC 컨트롤러에서 사용

3.@Service : 스프링 비즈니스 로직에서 사용

4. @Repository: 스프링 데이터 접근 계층에서 사용

5. @Configuration: 스프링 설정 정보에서 사용 

 

이 어노테이션들도 스캔 대상으로 포함되는 이유는 아까 Configuration의 경우에서도 설명한것과 같은 맥락입니다.

모두, 어노테이션을 들여다보면 @Component라는 어노테이션을 포함하고 있습니다. 

 

 

+useDefaultFilters 옵션이 있는데 이는 기본값으로 켜져 있으며, 이걸 끄면 스캔대상에서 빠진다. 

 

 

 

 

수동 등록 vs 자동 등록

 

 

이제 @Component를 통한 자동 빈 등록을 배웠는데, 그렇다면 수동 등록과 자동 등록을 중복으로 사용한다면?

 

그럴 일은 거의 없겠지만, 만약 자동 빈으로 등록하고 수동으로 빈을 등록하는 방식모두 사용한다면 

오류가 발생할 수 있다. 

 

만약 수동으로 이미 존재하는 빈에 추가로, 자동으로 스프링 빈을 등록했는데, 그 이름이 같은 경우 스프링은 

`ConflictingBeanDefinitionException`이라는 예외를 발생시킨다. 

 

반대로, 자동 빈 등록 이후에 수동 빈 등록을 시도했는데 이름이 같다면? 

자동 빈
수동 빈

 

결과는 이 경우 수동 빈 등록이 우선권을 가진다. (수동 빈이 자동 빈을 오버라이딩 해버린다.)