인프런 강의 中
김영한 강사님의 '스프링 핵심 원리' 내용을 정리했습니다.
이전 시간에 우리는 스프링 컨테이너가 자동으로 구성해주는 Singleton에 대해서 공부했다. 이번 섹션에서는 또!! 스프링에서 제공하는 강력한 기능을 공부할 예정이다. 바로 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능이다. 김영한 강사님의 명강을 들으며 오늘도 열심히 달려보자!
목차
- 컴포넌트 스캔과 의존관계 자동 주입 시작하기
- 탐색 위치와 기본 스캔 대상
1. 컴포넌트 스캔과 의존관계 자동 주입 시작하기
우리는 지금까지 빈 등록을 위해서 클래스 파일이나 XML 파일로 빈 설정 정보를 작성했다.
빈을 수동으로 설정했던 내용이 기억이 나지 않는다면 아래 포스팅 글 참조!
Section4(1편) 스프링 컨테이너와 스프링 빈
인프런 강의 中 김영한 강사님의 '스프링 핵심 원리' 내용을 정리했습니다. Section3까지는 OCP, DIP를 지키는 코드를 순수 자바 코드로도 작성해보고 스프링을 사용한 코드로 리팩토링도 해보았다.
ntweety.tistory.com
우리는 지금까지 4~5개 정도의 빈 등록을 했기 때문에 해당 작업이 번거롭지 않았지만 수동으로 등록해야 하는 빈이 수십, 수백개가 되면 일일이 등록하기도 귀찮고, 설정 정보도 커지고, 누락하는 문제도 발생한다. 그래서! 스프링 컨테이너는 이렇게 번거로운 작업을 자동으로 해주는 컴포넌트 스캔이라는 기능을 제공한다! 그저 감사할 따름이다.. 코드가 어떻게 달라지는지 새로운 AppConfig 파일을 만들어서 비교해보자.
우선 excludeFilters 부분은 신경쓰지 말고 코드를 살펴보자.(현재는 없어도 되는 코드) 엄청 깔끔하지 않는가? 그냥 어노테이션이 붙은 것 외에는 아무런 코드도 없다. 이렇게 아무것도 작성하지 않아도 자동으로 빈 등록을 해주는 것이 @ComponentScan의 힘이다. 여기서 당연히 @ComponentScan이 아무런 신호도 주지 않았는데 무작정 빈 등록을 하진 않는다. 컴포넌트 스캔은 이름 그대로 @Component 어노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다. 그러니 빈 등록을 하고 싶은 구현체 클래스에는 @Component를 붙여주자!
참고: @Configuration이 컴포넌트 스캔의 대상이 된 이유도 @Configuration 소스코드를 열어보면 @Component 어노테이션이 붙어있기 때문이다.
그럼 이제 자동으로 빈 등록 대상이 될 수 있도록 등록해야 할 클래스에 @Component 어노테이션을 붙여주자
MemoryMemberRepository @Component 추가
@Component
public class MemoryMemberRepository implements MemberRepository {}
RateDiscountPolicy @Component 추가
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
MemberServiceImpl @Component 추가
@Component
public class MemberServiceImpl implements MemberService {}
OrderServiceImpl @Component 추가
@Component
public class OrderServiceImpl implements OrderService {}
위와 같이 추가하면 컴포넌트스캔이 @Component 어노테이션이 붙은 파일을 찾고 빈 등록을 자동으로 해준다! 그럼 이제 빈 등록 끝~~ 이라고 하면 스프링 컨테이너 수업부터 다시....ㅎㅎ 우리는 생성자 주입을 통해서 AppConfig 파일에서 의존성을 주입시켜줬다. 위 작업까지만 한다면 의존성 주입을 생각하지 않은 것이다. 그럼 의존성 주입은 어떻게 하는가? 기껏 역할과 구현으로 분리 시켰는데 다시 구현체에서 어떤 구현체를 사용할지 정해야 하는가??? 아니다. 의존성 또한 자동으로 주입시켜주도록 코드를 작성하면 된다. 이 때, 사용하는 코드가 @Autowired이다.
생성자에 @Autowired를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다. 이것이 Autowired의 역할이다. 이 때, 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다. 그럼 한 번 자동으로 의존성을 주입할 수 있도록 Autowired 어노테이션을 사용해보자.
MemberServiceImpl @Autowired 추가
@Component
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
OrderServiceImpl @Autowired 추가
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
위와 같이 @Autowired를 생성자 위에 붙여주면 생성자를 통해서 자동으로 의존성 주입을 할 수 있다. 그런데 여기서 필자는 @Auowired를 기입하지 않고 테스트를 해보았는데 성공했다. 궁금증이 발동해 인터넷에 검색해보니 생성자가 하나만 정의되어 있고 스프링 빈이라면 @Autowired 어노테이션을 생략해도 자동으로 의존성 주입을 시켜준다는 내용이 있었다. 그래서 우리가 작성한 코드로 따지면 @Autowired를 생략해도 무방하다!
컴포넌트 스캔과 자동 의존관계 주입이 어떻게 동작하는지 김영한 강사님의 명화를 통해 이해해보자.
2. 탐색 위치와 기본 스캔 대상
탐색할 패키지의 시작 위치 지정
모든 자바 클래스를 다 컴포넌트 스캔하면 시간이 오래 걸린다. 그래서 꼭 필요한 위치부터 탐색하도록 시작 위치를 지정할 수 있다.
@ComponentScan(
basePackages = "hello.core";
}
- basePackages : 탐색할 패키지의 시작 위치를 설정한다. 설정한 패키지부터 탐색 시작. 내림차순 탐색
- basePackages = {"hello.core", "hello.service"} 이렇게 여러 시작 위치를 지정할 수도 있다.
- 만약 지정하지 않으면 @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
참고: 스프링 부트를 사용하면 스프링 부트의 대표 시작 정보인 @SpringBootApplication를 이 프로젝트 시작 루트 위치에 두는 것이 관례이다.(그리고 이 설정안에 바로 @ComponentScan이 들어있다.)
컴포넌트 스캔 기본 대상
@Component를 소스 코드로 가지며 많이 사용되는 어노테이션은 다음과 같다.
- @Component: 컴포넌트 스캔에서 사용
- @Controller: 스프링 MVC 컨트롤러에서 사용
- @Service: 스프링 비즈니스 로직에서 사용
- @Repository: 스프링 데이터 접근 계층에서 사용
- @Configuration: 스프링 설정 정보에서 사용, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 함.
참고: 사실 어노테이션에는 상속관계라는 것이 없다. 그래서 이렇게 어노테이션이 특정 어노테이션을 들고 있는 것을 인식할 수 있는 것은 자바 언어가 지원하는 기능이 아니라 스프링이 지원하는 기능이다.
'스프링 > SpringBasicCore' 카테고리의 다른 글
Section7(2편) 의존관계 자동 주입(옵션 및 lombok 활용) (4) | 2024.03.08 |
---|---|
Section7(1편) 의존관계 자동 주입 종류 (3) | 2024.03.08 |
Section5 Singleton (0) | 2024.02.21 |
Section4(3편) BeanDefinition (1) | 2024.02.20 |
Section4(2편) BeanFactory와 ApplicationContext (0) | 2024.02.07 |