[기본기] 7-3. @Component, @Autowired

khyojun·2022년 10월 3일
1
post-thumbnail

본 게시글은 김영한님의 스프링 핵심 원리 기본편을 정리한 글입니다.


📌 이제 가벼워질 시간 (@ComponentScan, @Autowired)

이때까지 자바 코드나 Xml코드를 통하여서 설정 정보를 @Configuration을 통하여서 빈을 등록하고 하였는데 실제로는 이렇게 보다도 Bean이 대규모의 코드에서는 몇 개를 등록을 해야 하나? 라고 잠깐만 생각을 해봐도 이 코드를 작성하고 유지 보수하는 입장에서는 상당히 귀찮고 관리하기도 어렵고 할 것 같다는 생각이 든다. 그리고 언제 이걸 일일이 등록을 다 할 거냐...
그래서 스프링에서는 설정 정보 없이도 자동으로 스프링 빈을 등록하는 방법이 있다고 한다.

그게 바로 컴포넌트 스캔이라는 기능이다. 또한 DI도 @Autowired를 통하여서 자동적으로 의존관계를 주입시켜준다.

그래서 이제부터 @ComponentScan을 활용하여 코드들을 수정하여보자.

우선은 설정 정보를 담당하던 AppConfig를 새롭게 바꿔보자.

📂AutoAppConfig

@Configuration
@ComponentScan(
        basePackages = "practicecore.ptcore",
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {

}

excludeFilter관련 정보로 @Configuration이 겹치는 것을 방지하기 위하여서 제외를 시켜줬다.

여기에 추가로 빈으로 등록될 클래스들에 @Component를 붙여준다.

@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;
    }
    
 @Component
public class MemoryMemberRepository implements MemberRepository

@Component
public class MemberServiceImpl implements MemberService{

    MemberRepository memberRepository;

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

@Component
public class RateDiscountPolicy implements DiscountPolicy

그리고 각자 @Component를 지정하여주고 그리고 의존관계를 주입하여줘야하는 곳에 @Autowired를 작성하여 DI를 해주었다. 그리고 참 편리한 것이 @Autowired하나만 작성을 하여주면 그 안에 파라미터가 몇 개가 있든 알아서 주입을 시켜준다고 한다.

지금 이렇게 하여줄때 상황은 다음과 같다.

✔ 스프링 컨테이너 상황

빈 이름빈 객체
memberServiceImplMemberServiceImpl@x01
orderServiceImplOrderServiceImpl@x02
rateDiscountPolicyRateDiscountPolicy@x04
memoryMemberRepositoryMemoryMemberRepository@x03

@ComponentScan은 @Component가 붙은 모든 클래스들을 스프링 빈으로 등록을 하였다. 그리고 빈을 등록을 할 때 자동적으로 그 클래스의 맨 앞글자만 소문자로 변경이 되어 등록이 된다.
EX) MemberServiceImpl -> memberServiceImpl
그치만 꼭 이렇게 저장하고 싶지 않다면 @Component("원하는 이름 ") 같은 형식으로 이름을 지정하여주면 된다.

🔍 @Autowired되는 과정

@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy)
이렇게 지정을 하게 될 경우 옆에 있는 MemberRepository, DiscountPolicy와 같은 타입의 빈을 자동적으로 찾아서 자동으로 주입을 시킨다.(스프링 컨테이너에 등록된 빈) 그렇게 따지면 MemberRepository, DiscountPolicy는 @Component로 등록을 안했는데요? 라고 물어볼 수 있지만 조회를 한다는 것의 전략이 ac.getBean(MemberRepository.class)이렇게 부르는 것과 비슷하다. 그렇기에 MemberRepository의 하위에 있는 MemoryMemberRepository 그리고 DiscountPolicy -> RateDiscountPolicy를 주입을 시켜주게 된다.

MemberRepository 타입 찾기 -> MemoryMemberRepository
DiscountPolicy 타입 찾기 -> RateDiscountPolicy

❗ @ComponentScan을 하면 모든 패키지들을 다 조회를 해서 찾나?

이것에 대한 대답을 하자면 또 그런 건 아니다. @ComponentScan이 선언되어있는 클래스의 해당 패키지를 포함한 하위 패키지들에 있는 @Component를 다 찾는다고 한다. 그래서 @ComponentScan은 최대한 프로젝트의 최상단에 두는 것을 권장한다고 한다.
그렇지만 어떠한 패키지를 지정하여 그 패키지의 하위 패키지들을 조회를 다 하고 싶다면

@ComponentScan{
 basePackages = "hello.core",
}

이런 식으로 지정을 하여주면 된다. 그렇게 될 경우 hello.core.xxxx 같은 패키지에 있는 클래스들도 다 탐색하여 빈으로 등록을 하게 된다. 그래서 위에서 말했던 것처럼 프로젝트 메인 설정 정보는 대표적인 프로젝트의 정보이기 때문에 프로젝트의 시작 루트 위치에 두는 것을 최대한 권장을 한다.

  • 참고로 스프링부트를 사용하게 될 경우 @SpringBootApplication 안에 @ComponentScan이 들어있다. 그래서 시작 루트 위치에 두는 것이 관례라고 한다.

❗ @ComponentScan은 @Component만 찾는것은 아니다.

@ComponentScan은 @Component만 찾는것은 아니다. 다른 것의 종류는 다음과 같다.
@Controller : 스프링 MVC 컨트롤러에서 사용
@Repository : 스프링 데이터 접근 계층에서 사용
@Configuration : 스프링 설정 정보에서 사용
@Service : 스프링 비즈니스 로직에서 사용

근데 이것 하나하나 어노테이션에 대한 정보를 보기 위해서 들어가보면 다음과 같다.

@Component
public @interface Controller{
}

@Component
public @interface Service{
}

@Component
public @interface Repository{
}
@Component
public @interface Configuration{
}

각자 @Component를 포함을 하고 있었다. 이러니까 스캔을 한다는 것을 알 수 있었다.

오늘의 결론

스프링 정보를 등록하는 방법에 여러가지가 있지만 @Component, @Autowired를 적극적으로 활용을 하여 편하게 빈을 등록하자.

출처

  1. 김영한님의 스프링 핵심 원리 기본편(https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8)
profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글