ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring DI의 모든 방법 @Autowired / 생성자 주입
    Study/Spring 2019. 7. 17. 00:20

    Spring에서 등록된 Bean을 사용하기 위해서 DI(Dependency Injection)를 처리하는 방법은 크게 3가지가 있다.
    Field Injection, Setter Injection, Contructor Inject이다. Spring 3.x버젼까지만 해도 Setter Inject을 권장하였으나, 최근에는 순환참조, Coupling등이 문제로 인해서 Spring 4.3 이후 버젼 부터는 Contructor Inject를 권장하고 있다.

    Field Injection

    가장 간단한 방법으로 Bean으로 등록된 객체를 사용하고자 하는 클래스에 Field로 선언한 뒤 @Autowired키워드를 붙여주면 자동으로 주입된다.

    @Service
    public class BoardService {
    
        @Autowired
        private BoardDao boardDao;
    
        public void doSomething() {
            // ....
        }
    }

    동일한 Class의 Bean이 여러개 존재하는 경우는 아래와 같이 @Qualifier("myBoardDao")를 붙여주어 bean 이름을 지정하여 주입 받는 것이 가능하다.

    @Service
    public class BoardService {
    
        @Autowired
        @Qualifier("myBoardDao")
        private BoardDao boardDao;
    
        public void doSomething() {
            // ....
        }
    }

    매우 간단한 방법이지만, 단점이 많아서 권장되고 있지 않은 방법이다.

    1. 단일 책임의 원칙 위반
      의존성을 주입하기가 쉽다. @Autowired 선언 아래 3개든 10개든 막 추가할 수 있으니 말이다. 여기서 Constructor Injection을 사용하면 다른 Injection 타입에 비해 위기감 같은 걸 느끼게 해준다. Constructor의 파라미터가 많아짐과 동시에 하나의 클래스가 많은 책임을 떠안는다는 걸 알게된다. 이때 이러한 징조들이 리팩토링을 해야한다는 신호가 될 수 있다.

    2. 의존성이 숨는다.
      DI(Dependency Injection) 컨테이너를 사용한다는 것은 클래스가 자신의 의존성만 책임진다는게 아니다. 제공된 의존성 또한 책임진다. 그래서 클래스가 어떤 의존성을 책임지지 않을 때, 메서드나 생성자를 통해(Setter나 Contructor) 확실히 커뮤니케이션이 되어야한다. 하지만 Field Injection은 숨은 의존성만 제공해준다.

    3. DI 컨테이너의 결합성과 테스트 용이성
      DI 프레임워크의 핵심 아이디어는 관리되는 클래스가 DI 컨테이너에 의존성이 없어야 한다. 즉, 필요한 의존성을 전달하면 독립적으로 인스턴스화 할 수 있는 단순 POJO여야한다. DI 컨테이너 없이도 유닛테스트에서 인스턴스화 시킬 수 있고, 각각 나누어서 테스트도 할 수 있다. 컨테이너의 결합성이 없다면 관리하거나 관리하지 않는 클래스를 사용할 수 있고, 심지어 다른 DI 컨테이너로 전환할 수 있다. 하지만, Field Injection을 사용하면 필요한 의존성을 가진 클래스를 곧바로 인스턴스화 시킬 수 없다.

    4. 불변성(Immutability)
      Constructor Injection과 다르게 Field Injection은 final을 선언할 수 없다. 그래서 객체가 변할 수 있다.

    5. 순환 의존성
      Constructor Injection에서 순환 의존성을 가질 경우 BeanCurrentlyCreationExeption을 발생시킴으로써 순환 의존성을 알 수 있다.

    Setter Injection

    Setter Method@Autowired를 붙여서 DI를 구현하는 방식이다. (사실 꼭 setter method일 필요는 없다. 동일한 기능을 하는 다른 메소드 명도 상관 없다. = Method Injection이 정학한 이름)

    @Service
    public class BoardService {
    
        private BoardDao boardDao;
    
        @Autowired
        public void setBoardDao(BoardDao boardDao) {
            this.boardDao = boardDao;
        }
    }

    Spring 3.x 버젼에서까지 권장되었지만, 현재는 권장되는 방법은 아니다.

    Constructor Injection

    현재 가장 권장되고 있는 방법이다. 하나의 생성자가 존재시 기존 Field Injection의 거의 모든 단점을 극복해낸 패턴이다.

    @Service
    public class BoardService {
    
        private BoardDao boardDao;
    
        // @Autowired Spring 4.3 버젼 부터 @Autowired 생략가능
        public BoardService(BoardDao boardDao) {
            this.boardDao = boardDao;
        }
    }

    한가지 더 여기에 Lombok을 뿌리게 되면

    @Service
    @AllArgsConstructor
    public class BoardService {
    
        private BoardDao boardDao;
    
    }

    @AllArgsConstructor로 인해서 이렇게 간단하게 주입이 끝난다.
    만약 Immutability 이슈까지 해결하고 싶다면,

    @Service
    @RequiredArgsConstructor
    public class BoardService {
    
        private final BoardDao boardDao;
    
    }

    으로 완벽하게 해결할 수 있다.

    'Study > Spring' 카테고리의 다른 글

    @Configuration를 이용하여 Bean생성하기  (0) 2019.07.15

    댓글

Designed by Tistory.