롸?

DI(Dependency Injection) 개념 본문

Framework/Spring

DI(Dependency Injection) 개념

허니버터새우깡 2020. 4. 3. 10:20

1. 의존이란?

  스프링에서의 의존 주입을 이해하기 위해서는 '의존'의 의미부터 알아야 한다. 여기서 말하는 의존은 객체 간의 의존을 말한다. 다음 가정을 살펴보자.

 

회원 가입을 처리하는 기능을 구현한 Service 클래스가 있고, 이 클래스에서는 이메일의 중복체크를 위해서 이메일을 통해 회원 정보를 조회하는 MemberDao 클래스의 selectByEmail() 메소드를 이용한다. 이메일을 가진 회원 데이터가 있다면 회원 정보를 담은 Member 객체를 생성하고 MemberDao 객체의 insert() 메소드를 이용해 DB에 데이터를 삽입한다.

 

  위 케이스에서 눈여겨볼 점은 Service 클래스가 DB처리를 위해서 Dao클래스의 메소드를 사용한다는 것이다. 이렇게 한 클래스가 다른 클래스의 메소드를 실행할 때 이를 의존한다고 표현한다. 즉, 'Service 클래스가 Dao클래스에 의존한다'고 말할 수 있다. 의존은 변경에 의해 영향을 받는 관계이다. Dao의 insert() 메소드의 이름을 insertMember()로 변경하면 이 메소드를 사용하는 Service 클래스의 소스 코드도 함께 변경된다. 

  의존하는 대상이 있으면 그 대상을 구하는 방법이 필요하다. 가장 쉬운 방법은 의존 대상 객체를 직접 생성하는 것이다. 클래스 내부에서 new 를 사용해 직접 의존 객체를 생성하는 것은 쉽긴 하지만 유지보수 관점에서는 코드간의 강결합을 만들기 때문에 문제점을 유발할 수 있다. 또 다른 방법으로 DI와 서비스 로케이터를 통해서 의존 객체를 구할 수 있다. 스프링에서는 그 중 DI로 의존 객체를 구한다.

 

 

2. DI를 통한 의존 처리

  DI(Dependency Injection)는 의존하는 객체를 직접 생성하는 대신 의존 객체를 전달받는 방식을 사용한다. 의존성 주입은 IoC(Inversion of Control, 의존성 역전) 원칙을 하에 객체 간의 결합을 약하게 해주고 유지보수가 좋은 코드를 만들어 준다. 

위의 예제에서 의존 객체를 직접 생성하는 방식으로 Servie 클래스를 적용하면 다음과 같이 구현할 수 있다.

public class Service{

   private MemberDao memberDao = new MemberDao();
   
   public void regist(RegisterRequest req){
      Member member = memberDao.selectByEmail(req.getEmail());
      
      //회원이 존재하는 경우
      if(member != null){
         //이메일이 중복됨을 알림
      }
      
      //회원이 존재하지 않는 경우, 새 회원 등록
      Member newMember = new Member(req.getEmail(), req.getPassword(), req.getName());
      memberDao.insert(newMember);
   }
}

 

위 코드에서 DI를 적용하면 다음과 같이 구현할 수 있다.

public class Service{

   private MemberDao memberDao;
   
   public Service(MemberDao memberDao){
      this.memberDao = memberDao;
   }
   
   public void regist(RegisterRequest req){
      Member member = memberDao.selectByEmail(req.getEmail());
      
      //회원이 존재하는 경우
      if(member != null){
         //이메일이 중복됨을 알림
      }
      
      //회원이 존재하지 않는 경우, 새 회원 등록
      Member newMember = new Member(req.getEmail(), req.getPassword(), req.getName());
      memberDao.insert(newMember);
   }
}

 

  멤버 변수에서 new 연산자를 이용해서 직접 생성하는 부분이 사라지고 Service의 생성자에서 Dao 객체를 넘겨받고 있다.

  만약 회원 데이터의 빠른 조회를 위해 캐시를 적용하기 위해서 MemberDao클래스를 상속받은 CachedMemberDao 클래스를 만들어 적용시켜줘야 할 때, 직접 의존객체를 생성하는 경우는 Dao를 사용하는 모든 클래스에서 변경사항을 적용시켜야한다. 

  의존을 사용하는 경우 (가장 간단하게는) 메인에서 객체를 생성하는데 다음과 같은 코드로 객체를 생성하고 의존 객체를 전달 할 수 있다.

MemberDao memberDao = new MemberDao();
Service service = new Service(memberDao);

그리고 마찬가지의 변경사항이 생겼을 때는 new MemberDao(); 부분을 new CachedMemberDao(); 로만 변경해주면 된다. 

 

 

3. 객체 조립기

  main 메소드에서 의존 대상 객체를 생성하고 주입하는 방법이 나쁘진 않다. 이 방법보다 좀 더 나은 방법은 객체를 생성하고 의존 객체를 주입해주는 클래스를 따로 작성하는 것이다. 의존 객체를 주입한다는 것은 서로 다른 두 객체를 조립한다고 생각할 수 있는데, 이런 의미에서 이 클래스를 조립기라고 표현한다. 

 

그런 의미에서 스프링 작체가 DI를 지원하는 조립기라고도 볼 수 있다. xml, java config, annotation등 객체 조립하고 의존을 주입하는 여러가지 방법을 지원한다. 

 

 

 

 


참고 

1.  책 - 초보 웹 개발자를 위한 스프링5 프로그래밍 입문

Comments