본문 바로가기

웹/Spring

[메모] Spring 원리 (2) 컴포넌트 스캔, 의존관계 자동주입

 - 스프링 Annotation - 

  • 스프링에서는 컴포넌트 스캔을 통해 자동적으로 의존관계를 주입하도록 할 수 있다.
    • @Controller: 스프링 MVC 컨트롤러로 인식한다.
    • @Repository: 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해준다.
    • @Configuration: 앞서 보았듯이 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 한다.
    • @Service: 특별한 처리를 하지 X, 개발자들이 핵심 비즈니스 걔층을 인식하는데 도움을 준다.



 - ComponentScan FilterType - 

  • FilterType은 5가지 옵션이 있다.
    • ANNOTATION: 기본값, annotation을 인식해서 동작
    • ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작
    • ASPECTJ: AspectJ패턴 사용
    • REGEX: 정규 표현식
    • CUSTOM: 'TypeFilter'이라는 인터페이스를 구현해서 처리



 - 의존관계주입(DI) 방법 - 

  • 생성자 주입
    • 생성자(Constructor)를 통해 의존 관계를 주입
    • 생성자 호출시점에 단 1번만 호출되는 것이 보장
    • "불변, 필수" 의존관계에 사용
    • *중요 생성자가 단 1개만 있으면 @Autowired를 생략해도 자동 주입 (스프링 빈에만)
  • 수정자 주입 (setter 주입)
    • 수정자(setter)라 불리는 필드의 값을 변경하는 수정자 메서드를 통해 의존관계를 주입
    • "선택, 변경" 가능성이 있는 의존관계에 사용
    • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법
  • 필드 주입
    • 필드에 바로 주입하는 방법
    • 외부에서 변경이 불가능해 테스트하기 힘들다
    • 사용하지 말자!

 

 - 중복 빈 조회 - 

  • @Autowired 매칭
    • 타입 매칭
    • 타입 매칭의 결과가 2개 이상일 때는 필드 명으로 빈 이름 매칭
  • @Qualifier 매칭
    • @Qualifier끼리 매칭
    • 빈 이름 매칭
    • NoSuchBeanDefinitionException 예외 발생
  • @Primary 매칭
    • @Primary는 우선순위를 정하여, @Primary가 우선권을 갖게 된다.
```java
@Component
@Primary	// 우선권을 가짐
public class RateDiscountPolicy implements DiscountPolicy{}

@Component
public class FixDiscountPolicy implemnets DiscountPolicy{}
```

 

 - List, Map을 이용해 동적으로 빈사용- 

```java
public class AllBeanTest {

    @Test
    void findAllBean() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);

        DiscountService discountService = ac.getBean(DiscountService.class);
        Member winter = new Member(1L, "winter", Grade.VIP);
        int discountPrice = discountService.discount(winter, 10000, "fixDiscountPolicy");

        assertThat(discountService).isInstanceOf(DiscountService.class);
        assertThat(discountPrice).isEqualTo(1000);

        int rateDiscountPrice = discountService.discount(winter, 20000, "rateDiscountPolicy");
        assertThat(rateDiscountPrice).isEqualTo(2000);
    }

    static class DiscountService {
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;

        @Autowired
        public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;

            System.out.println("policyMap = " + policyMap);
            System.out.println("policies = " + policies);
        }

        public int discount(Member member, int price, String discountCode) {
            DiscountPolicy discountPolicy = policyMap.get(discountCode);
            return discountPolicy.discount(member, price);
        }
    }
}