-
spring[5] ComponentScan과 Component개인 공부/spring 2021. 5. 16. 08:48728x90반응형
Component Sacn
- 지금까지 빈을 등록하기 위해서 AppConfig class에 사용자가 일일히 @Bean으로 관리해주어야 했습니다. 하지만 이건 개발자에게 너무 귀찮은 작업이고 누락하게 되면 큰 장애가 발생하게됩니다. 그래서 Spring은 @Bean으로 일일히 등록하지 않아도 자동으로 스프링 빈으로 등록해주는 @ComponentScan과 @Component annotation을 제공합니다.
- 컴포넌트 스캔을 사용하게 되면 DI가 애매해집니다. 지금까진 수동으로 의존관계를 주입했지만 Bean이 자동으로 등록되게되니 의존관계를 설정할 수 있는 부분이 사라진것입니다. 그래서 @Autowired annotation을 지원한다. @Autowired에 대한 부분은 다음에 공부해보겠습니다.
- Component Scan 적용해보기
기존의 AppConfig처럼 @Bean으로 등록하고 DI를 설정할 필요도 없이 끝났습니다. ㅎㅎ @ComponentSacn으로만 끝난거지만 만약 저와 같은 예제를 작성중이신 분들은 excludeFilters를 꼭 입력해주셔야하는데요. 그 이유는 우리가 이미 AppConfig라는 스프링 컨테이너를 하나 더 만들어놨기 때문에 동시에 등록이 되지 않도록 설정해주는 것입니다.@Configuration @ComponentScan( //우리가 이미 등록해놓은 AppConfig를 등록하지 않도록 excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) ) public class AutoAppConfig { }
- AppConfig와 같은 위치에 AutoAppConfig class를 만들고 다음과 같이 설정합니다.
- Component 적용해보기우리가 빈으로 관리했던 class들에게 @Component를 붙여주면 @ComponentScan이 알아서 스프링 컨테이너에 모두 등록해줍니다! 그리고 여기서 컨테이너에 등록할때 빈 이름의 기본 전략이 있는데요 첫글자는 소문자로 변형한 뒤 모두 그래도 가게 됩니다. 위의 예시의 경우 MemberServiceImpl -> memberServiceImpl로 등록되어 집니다. 빈 이름을 직접 등록할 수도 있는데요 @Component("빈 이름")으로 등록해주면 @Bean으로 등록할때 이름을 변경했던것 처럼 사용하실 수 있습니다.
@Component public class MemberServiceImpl implements MemberService{ private final MemberRepository memberRepository; @Autowired public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Override public void join(Member member) { memberRepository.save(member); } @Override public Member findMember(Long memberId) { return memberRepository.findById(memberId); } //테스트용 public MemberRepository getMemberRepository(){ return memberRepository; } }
- 컴포넌트 스캔 위치컴포넌트 스캔의 탐색 위치를 basePackages를 통해 지정할 수 있는 것인데요. 프로젝트 구조상 정말 필요하다면 사용하길 권장드립니다. basePackages의 default값은 @ComponentScan이 사용된 class의 package값을 default로 가지고 가기 때문에 일반적으로 또 spring boot에서 기본적으로 제공되는 프로젝트 구조가 프로젝트의 최상단으로 지정하시는걸 권장합니다.
@ComponentScan( basePackages = "hello.core", }
- @Contorller, @Service, @Repository@SpringBootApplication@Service
- 여기까지 공부하시면서 프로젝트를 진행하고 계셨거나 회사에서 프로젝트를 진행하고 계신분들은 어? 우리 프로젝트는 @Component를 쓴적이 없고 @ComponentSacn도 안쓰는데 도대체 어떻게 스프링 컨테이너를 사용하고 있는거지? 우리 회사는 싱글톤으로 디자인되지 않고 객체를 무한히 생성하는건가??? 망했다 라고 생각하실 수 있는데요. 사실 그렇지 않습니다. Spring boot 프로젝트의 경우 최초 생선된 @SpringBootApplication 내부에 @ComponentScan이 들어있고 @Controller와 @Service, @Repository에는 @Component가 포함되어 있습니다.
- Filter
- includeFilters
- 컴포넌트 스캔 대상으로 추가
- excludeFiltersincludeFilters는 @Component가 있으면 자동으로 스캔이 되니 사용할 일이 별로 없구요. excludeFilters의 경우 실무에서 가끔 사용된다고 하네요!
- 컴포넌트 스캔 대상에서 제외
- filter 사용법다음과 같이 filter에 type과 class를 지정해주시면 됩니다.
@ComponentScan( includeFilters = @Filter(type = FilterType.ANNOTATION, classes = IncludeComponent.class), excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = ExcludeComponent.class) )
- filter type 옵션
- ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.
- ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
- ASPECTJ: AspectJ 패턴 사용
- REGEX: 정규 표현식
- CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리
- 필터를 통해 컴포넌트의 스캔의 대상에 추가할수도 제외할수도 있는데요.
- 중복 등록과 충돌
- 자동 빈 등록 + 자동 빈 등록
- 수동 빈 등록 + 자동 빈 등록2번의 경우 수동빈의 등록이 우선되며 자동 빈이 overriding됩니다. spring으로만 실행하게되면 실행이 되지만 최근 spring boot의 경우 이 경우도 에러로 처리합니다. 그 이유는 이렇게 되면 설정이 꼬이게 되어서 개발자가 잡기 어려운 버그를 만들어내기 때문입니다.
- 1번의 경우 ConflictingBeanDefinitionException 예외가 발생하게 되며 빈의 이름을 수정해야합니다.
- 만약 컴포넌트 스캔에 같은 이름의 빈을 중복으로 등록하게 되면 어떻게 될까요?
728x90반응형'개인 공부 > spring' 카테고리의 다른 글
spring[7] @Bean 생명주기 (0) 2021.05.20 spring[6] DI 의존관계 주입 (0) 2021.05.19 Spring[4] Spring의 Singleton Container (0) 2021.05.15 Spring[3] Spring Container와 Spring bean (0) 2021.05.15 spring[2] Spring을 사용하지 않은 Java Web Project (0) 2021.05.14