[DI] JdbcContext의 특별한 DI

Ader(아더)·2022년 4월 13일
0

Spring

목록 보기
5/6

토비의 스프링 스터디를 진행하며 3장에서 더 알아보고 싶은 내용으로 위와 같은 주제를 정했다.
이제부터 자세히 알아보자!

1. JdbcContext의 특별한 DI

  • UserDao에서 JdbcContext를 DI 받는 방법
    • 생성자 주입을 사용한다. 하지만 인터페이스의 구현없이 클래스를 직접 DI하고 있다.
    • 생성자 주입의 의도는 런타임시에 구현체가 동적으로 선택되는 것, 하지만 이 경우에는 클래스 레벨부터 특정 클래스가 고정되어 있고 구현체의 변경이 불가능하다.

2. 스프링 빈으로 DI

  • 인터페이스를 사용하지 않고 DI를 적용하는 것은 문제가 없을까?
    • 스프링 DI의 기본의도에 맞게 인터페이스를 만들고 이를 UserDao에서 사용해도 상관없다. 하지만 꼭 그럴 필요는 없다.
    • 스프링의 DI는 넓게 보자면 객체의 생성과 관계설정에 대한 제어권한을 오브젝트에서 제거하고 외부로 위임했다는 IoC개념을 포괄한다.
      • 이 예제에서는 JdbcContext를 스프링을 이용해 UserDao 객체에서 사용하게 주입했다는 건 DI의 기본을 따르고 있다고 볼 수 있다.
  • JdbcContextUserDao와 DI 구조로 만들어야 하는 이유
    • JdbcContext는 그 자체로 변경되는 상태정보가 없다. 따라서 싱글톤으로 구현하는 것이 알맞다! (dataSource가 있지만 읽기전용이기 때문에 상관없음)
    • JdbcContext가 DI를 통해 다른 빈에 의존하고 있기 때문이다.
      • JdbcContextDataSource를 DI받고 있다.
      • DI를 위해서는 양쪽 빈 둘다 스프링 빈에 등록되어야한다.
      • 실제 스프링에도 드물지만 이런 사례들이 있음
  • 왜 인터페이스를 사용하지 않았을까?
    • 인터페이스가 없다는 건 UserDaoJdbcContext가 매우 강한 결합도를 갖는다는 것이다. 항상 두 클래스는 같이 사용되어야 한다.
    • JdbcContext는 테스트에서도 다른 구현으로 대체해서 사용할 이유도 없고 그럴 일도 없다. 이런 경우에는 굳이 인터페이스를 만들 필요없이 강력한 결합관계를 갖도록 코딩해도 된다. 단, 이는 최후에 선택되어야 하는 선택지이다. (절대로 귀찮아서 안만드는 것은 안된다)

3. 코드를 이용하는 수동 DI

  • UserDao 내부에서 직접 DI
    • 싱글톤 포기
      • 그렇다고 매번 DAO 메소드 호출 때마다 객체를 새로 만드는 것은 아니다.
      • DAO 클래스 하나 마다 하나의 JdbcContext 오브젝트를 갖고 있게 하는 것이다. 대형 프로젝트여도 수백개면 충분하기 때문에 별 문제가 없다.
    • 스프링 빈이 아니므로 UserDao가 직접 자기가 사용할 JdbcContext를 만들고 초기화하는 전통적인 방법 사용
      • 임시로 UserDao를 DI 컨테이너처럼 동작하게 만드는 것!
      • DataSourceUserDao가 대신 받아 주입해준다
      • UserDaoDataSource만 빈이다.
      public class UserDao {
      ...
      
      	private JdbcContext jdbcContext;

		public void setDataSource(DataSource dataSource) {
          this.jdbcContext = new JdbcContext();
          
		  this.jdbcContext.setDataSource(dataSource); 
          this.dataSource = dataSource;
      }
  • 장점
    • 인터페이스가 필요없을 정도의 강한 결합도를 갖는 DAO와 JdbcContext를 어색하게 따로 빈으로 분리하지 않고 내부에서 직접 만들어 사용하면서 다른 오브젝트를 DI 할 수 있다는 것!
      • 스프링에서 종종 활용되는 기법

4. 정리

  • JdbcContext와 같이 인터페이스를 사용하지 않고 DAO와 밀접한 관계를 갖는 클래스를 DI에 적용하는 방법 두 가지
    • 인터페이스를 사용하지 않지만 스프링 DI를 위해 빈으로 등록해 사용하는 방법
      • 오브젝트 사이의 실제 의존관계가 설정파일에 명확하게 드러난다는 장점
      • DI의 근본적인 원칙에 부합하지 않는 구체적인 클래스와의 관계가 설정에 직접 노출된다는 단점
    • DAO의 코드를 이용해 수동으로 DI 하는 방법
      • JdbcContextUserDao의 내부에서 만들어지고 사용되면서 그 관계를 외부에는 드러내지 않는다는 장점
      • JdbcContext를 여러 오브젝트가 사용하더라도 싱글톤으로 만들 수 없고, DI 작업을 위한 부가적인 코드가 필요하다는 단점

일반적으로 권장되는 방법은 없다.
하지만 본인이 선택한 방법에 대해 왜 그렇게 선택했는지에 대한 분명한 이유와 근거를 댈 수 있어야한다.
자신없으면 그냥 인터페이스를 만들어서 평범하게 DI를 구현하라

profile
하루하루 성장하는 개발자

0개의 댓글