-
[Spring Boot] 컴포넌트 스캔과 의존관계 자동 주입Back-End/Spring Boot 2022. 10. 3. 18:34
📑 @ComponentScan 이란?
아래 코드를 보면 스프링 빈을 등록할 때는 @bean을 통해 설정 정보에 직접 등록할 스프링 빈을 나열했다. 예제에서는 몇개 안되었지만, 만약 수천개, 수만개가 되면 일일이 등록하기 귀찮고, 설정 정보도 커지게 된다. 그럴 때 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다. 또한 의존관계도 자동으로 주입하는 @Autowired라는 기능을 제공한다.
더보기스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성) 정보로 사용한다. 여기서 @Bean이라 적힌 메서드를 모두 호출해 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라고 한다.
//구성 정보, 설정 정보에 Configuration 어노테이션을 붙여준다. //스프링 컨테이너가 관리하기 위해 이 어노테이션이 필요!! @Configuration public class AppConfig { //key는 메서드 이름 memberService() //value는 return 값으로 스프링 컨테이너에 등록된다. @Bean public MemberService memberService(){ System.out.println("call AppConfig.memberService"); return new MemberServiceImpl(memberRepository()); } }
🔨 위의 @Bean을 통해 스프링에 빈을 등록했던 코드를 컴포넌트 스캔과 의존관계 자동 주입 코드로 바꿔보자.
package hello.core; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration //@ComponentScan : @Component 에너테이션이 붙은 클래스들을 찾아가 다 스캔한다. @ComponentScan( //다 스캔하는데 이 클래스는 제외하고 스캔한다. //AppConfig에 @Configuration이 붙어있는데 이는 우리가 수동을로 주입한 클래스이므로 //현재 자동으로 테스트하기 위해서 제외한다. 즉) 충돌 방지 excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class) ) public class AutoAppConfig { }
컴포넌트 스캔을 사용하려면 먼저 @ComponentScan을 설정 정보에 붙여주면 된다. 기존의 AppConfig와는 다르게 @Bean으로 등록한 클래스가 하나도 없다.
📌컴포넌트 스캔을 사용하면 @Component 애노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다.
추가로 @Configuration이 붙은 설정 정보도 자동으로 등록되기 때문에 위의 예제에서 우리는 AppConfig에 수동으로 빈을 설정해두었으므로 충돌을 방지하기 위해 excludeFilters를 이용해 설정 정보는 컴포넌트 대상에서 제외한다.
이제 빈으로 등록할 클래스들이 컴포넌트 스캔에 대상이 되도록 @Component 애노테이션을 붙여주며, 생성자에는 @Autowired를 붙여준다.
package hello.core.member; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class MemberServiceImpl implements MemberService{ // private final MemberRepository memberRepository = new MemoryMemberRepository(); private final MemberRepository memberRepository;//DIP를 지키며 추상화에만 의존 @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;} }
테스트를 통해서 memberService가 MemberService.class로 형변환 가능한지 해보면, 컴포넌트 스캔이 잘 동작하는 것을 확인할 수 있다.
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class); MemberService memberService = ac.getBean(MemberService.class); Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
📑 @ComponentScan과 의존관계 주입
📌 1. @ComponentScan
: 컴포넌트스캔은 컴포넌트가 붙은 모든 클래스를 스프링 빈으로 등록한다. 이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다. ex) MeberServiceImpl - > memberServiceImpl 만약, 직접 스프링 빈 이름을 지정하고 싶으면 @Component("memberService2") 이런 식으로 부여하면 되지만 보통 기본값을 사용한다.
📌 2. @Autowired 의존관계 자동 주입
생성자에 @Autowired를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다. 이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다. getBean(MemberRepository.class)와 동일하다고 보면 된다. 생성자의 파라미터가 많아도 다 찾아서 자동으로 주입한다.
📑 @ComponentScan 탐색 위치와 기본 스캔 대상
모든 자바 클래스를 다 컴포넌트 스캔하면 시간이 오래 걸린다. 그래서 꼭 필요한 위치부터 탐색하도록 시작 위치를 지정할 수 잇다.
@ComponentScan{
backPackages = "hello.core", "hello.service}만약 지정하지 않으면 @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다. 보통 따로 패키지 위치를 지정하지 않고 설정 정보 클래스의 위치를 프로젝트 최 상단에 두는 것이다. 예를들어 프로젝트가 다음과 같은 구조라면
com.hello
com.hello.service
com.hello.repositorycom.hello -> 프로젝트 시작 루트, 여기에 AppConfig 같은 메인 설정 정보들을 두고, @ComponentScan 애너테이션에 basePackages 지정은 생략한다. 이렇게 하면 com.hello를 포함한 하위는 모두 자동으로 컴포넌트 스캔의 대상이 된다.
📑. 컴포넌트 스캔 대상
컴포넌트 스캔은 @Component뿐만 아니라 다음과 같은 내용도 추가로 대상에 포함된다.
@Component : 컴포넌트 스캔에서 사용
@Controller : 스프링 MVC 컨트롤러에서 사용, 스프링 MVC 컨트롤러로 인식
@ Service : 스프링 비즈니스 로직에서 사용, 사실 서비스는 특별한 처리를 하지 않지만, 개발자들이 핵심 비즈니스 로직이 여기에 있겠구나 라고 비즈니스 계층을 인식하는데 도움이 된다.
@Repository : 스프링 데이터 접근 계층에서 사용, 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환시켜 준다.
@Configuration : 스프링 설정 정보에서 사용, 스프링 빈이 싱글톤을 유지하도록 추가처리를 한다.반응형'Back-End > Spring Boot' 카테고리의 다른 글
[Spring Boot] 빈 스코프 범위 (싱글톤, 프로토타입, 웹) (0) 2022.10.06 [Spring Boot] 생성자 주입이란? + @Autowired 옵션 처리 (1) 2022.10.04 [Spring Boot] 싱글톤 패턴 vs 싱글톤 컨테이너 ( @Configuration) (1) 2022.10.01 [Spring Boot] 스프링 컨테이너 ApplicationContext 생성과 빈 등록, 의존 관계 설정 (0) 2022.09.30 [JAVA 객체 지향 설계의 원칙] OCP, DIP 예제로 완전 정복 ( + 관심사 분리) (0) 2022.09.30