프레임워크/Spring

#4 Spring 의존성 주입 방법

Scala0114 2022. 4. 27. 22:03

1. @Autowired

  • @Autowired 어노테이션을 사용하지 않을 때의 의존성 주입

    <!-- XML 설정파일 -->
    <!-- 생성자를 통한 의존성 주입 -->
    <bean id="itemRepository" class="com.example.SampleProject.service.ItemService">
        <constructor-arg ref="itemRepository"/>
    </bean>
    
    <!-- Setter를 통한 의존성 주입 -->
    <bean id="itemRepository" class="com.example.Sample.service.ItemService">
        <property name="itemRepository" ref="itemRepository"/>
    </bean>
    
    • XML 파일에 bean을 주입받을 클래스를 태그를 사용하여 등록

    • bean을 주입받을 클래스는 생성자와 Setter중 어느쪽을 통해 주입받을지 선택

       

  • @Autowired 사용시 의존성 주입

    • 의존성을 주입받아야할 부분에 @Autowired 어노테이션 사용
    • Spring은 bean 컨테이너에서 매칭되는 타입의 bean을 찾아 자동으로 의존성을 주입

     

  • @Qualifier

    • 같은 타입의 bean이 복수 존재할 경우 어느것을 주입받을지 명시하기 위한 어노테이션
    • @Autowired와 함께 @Qualifier('<bean이름>') 을 붙여주면 해당 bean을 주입받을 수 있음
    • 같은 타입의 bean이 여러개일 때 Qualifier를 설정하지 않으면 에러가 발생
    • 해당 타입의 bean이 유일하게 존재하더라도 Qualifier와 매칭되지 않으면 주입받을 수 없음

 

 

2. 세 가지 주입 방식(@Autowired 사용 기준)

  • 생성자를 통한 주입

    package com.example.SampleProject.service;
    
    public class ItemService {
        private final ItemRepository itemRepository;
    
        @Autowired
        public ItemService(ItemRepository itemRepository) {
            this.itemRepository = itemRepository;
        }
    }
    
    • 의존성을 주입받을 필드를 선언

    • bean을 인자로 받아 필드를 초기화하는 생성자를 정의

    • 생성자에 @Autowired 를 사용

    • 생성자가 하나뿐일 경우 @Autowired는 생략 가능

    • 초기화 과정을 거치기 때문에 의존성을 주입받을 필드를 final로 선언할 수 있음

    • 생성 이후에 다른 의존성을 주입하는 것은 불가능

       

  • Setter를 통한 주입

    package com.example.SampleProject.service;
    
    public class ItemService {
        private ItemRepository itemRepository;
    
        @Autowired
        public setItemService(ItemRepository itemRepository) {
            this.itemRepository = itemRepository;
        }
    }
    
    • 생성자 주입과 유사한 구조이나 생성자 대신 Setter를 사용

    • 생성과 동시에 초기화되는 것이 아니기 때문에 final 사용 불가

    • 생성 이후에도 Setter를 사용하여 다른 의존성 주입 가능

       

  • 필드에 직접 주입

    package com.example.SampleProject.service;
    
    public class ItemService {
        @Autowired
        private ItemRepository itemRepository;
    
    }
    
    • 필드에 직접 @Autowired를 붙여줘도 의존성 주입 가능

    • 생성과 동시에 초기화되는 것이 아니기 때문에 final 사용 불가

    • 필드 주입을 지원하는 프레임워크의 존재에 의존적

    • 외부에서 필드에 접근 불가

       

  • Spring에서는 생성자를 통한 주입을 사용할 것을 권장

     

  • 생성자 주입을 사용해야하는 이유?

    • Compile Time에서의 순환 참조 검출

      • 필드 주입, Setter주입의 경우 객체 생성시에 바로 의존성을 주입하지 않음
        => 순환 참조가 발생하는 클래스에 의존하더라도 compile time에서는 에러가 발생하지 않음

         

      • 생성자 주입의 경우 객체 생성 시점에서 의존성을 주입
        => 객체가 생성되는 순간 순환 참조 에러가 검출, compile time에 에러를 발견할 수 있음

         

    • Immutable한 객체 보장 가능

      • 생성자 주입에서는 final을 사용하여 주입받은 객체가 불변임을 보장할 수 있음

      • 생성시에 주입받은 객체가 변경되어야 하는 경우는 극히 드물기 때문에 유용

         

    • 편리한 테스트코드 작성

      • 필드 주입과 달리 생성자는 생성시에 한해 프레임워크의 도움 없이 직접 의존성 주입 가능
      • 테스트용 Mock 클래스를 사용하여 생성자를 호출하는 것으로 간단하게 테스트 코드 작성 가능

 

 

3. @Resource

  • Java 표준이 지원하는 의존성 주입용 어노테이션

  • @Autowired 와 달리 Spring 프레임워크를 사용하지 않아도 사용 가능

     

  • Bean 탐색 순서의 차이

    • @Autowired

      • Type이 일치하는 Bean을 먼저 탐색

      • 없을 경우 에러 발생

      • Type이 일치하는 Bean이 하나라면 바로 주입

      • Type이 일치하는 Bean이 복수 존재할 경우 id로 구분

      • id가 매칭되는 Bean이 하나라면 바로 주입

      • id로도 하나의 Bean을 특정할 수 없을 경우 에러 발생

      • @Qualifier를 통해 id를 지정 가능

         

    • @Resource

      • @Autowired와 유사하나 Type과 id의 우선순위가 역전
      • 어노테이션의 name 속성(attribute)값으로 id 지정 가능