ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [spring] DI와 자동 의존 주입(@Autowired) 박살내기();
    Spring 2020. 2. 20. 05:46
    반응형
    스프링 프레임워크의 핵심 기능인 DI가 무엇이고?
    자동 의존 주입의 종류와 사용법은 무엇인고?
    어떠한 자동 의존 주입 방식을 선택할꼬?

     

    DI(Dependency Injection)

    '의존성 주입'이라는 이해하기 어려운 용어로 번역될 수 있다... 가끔은 영어 그대로의 의미를 곰곰히 생각해보는게 한글보다 이해하기 더 편할때도 있는것 같다.. 주륵

    DI를 처음 접한 나의 표정..

    본론으로 돌아가서, 

    의존성 주입에서 '의존'은 객체간의 의존을 의미한다. 객체가 의존한다는 건 무엇일까?

    public class MemberService {
    
    	// 직접 생성
    	private MemberRepository memberRepository = new MemberRepository();
    	
    	public void register(Member member) {
    		memberRepository.insert(member);
    	}
    }

    위의 코드는 간단한 회원등록을 위한 service 클래스이며, DB 처리를 위해  MemberRepository 클래스의 메서드를 사용한다. 이때! 하나의 클래스가 다른 클래스의 메서드를 실행해야만 할 때 '의존' 한다고 표현한다.

    ex) MemberService 클래스는 MemberRepository 클래스에 의존한다.

     

    의존하는 대상을 사용하기 위해서는 사용하기를 원하는 클래스에서 new 연산자를 통해 필요한 대상을 직접 생성하는 것이 가장 쉽다. (위의 예시 처럼..) 하지만 직접 생성을 하는 것은 변경의 유연함이 떨어져 유지보수적인 관점에서 꽤나 문제점을 유발할 수 있다.

     

    그렇다면 생성자 또는 세터메서드를 통해 객체를 주입받아보자.

    public class Config {
    		
      MemberRepository memberRepository = new MemberRepository();
    
      // 생성자를 통해 의존성을 주입 하고자 할때
      MemberService memberService = new MemberService(memberRepository);
    
      // 세터 메서드를 통해 의존성을 주입 하고자 할때
      MemberService memberService = new MemberService();
      memberService.setMemberRepository(memberRepository);
    		
    }

     

    public class MemberService {
    
      private MemberRepository memberRepository;
    
      // 생성자를 통해 의존 객체 전달 받기
      public MemberService(MemberRepository memberRepository) {
      this.memberRepository = memberRepository;
      }
    
      public void register(Member member) {
      memberRepository.insert(member);
      }
    }
    
    public class MemberService {
    
      private MemberRepository memberRepository;
    
      // setter를 통해 의존 객체 전달 받기
      public void setMemberRepository(MemberRepository memberRepository) {
      this.memberRepository = memberRepository;
      }
    
      public void register(Member member) {
      memberRepository.insert(member);
      }
    }

    설정클래스(예시로는 Config 클래스)를 통해 MemberRepository 클래스를 외부에서 생성하고 생성자 또는 세터 메서드를 통해 MemberService 객체에 생성함과 동시에 의존성을 주입한다. 유지보수측면에서는 객체를 생성하고 주입해주는 Config 클래스만 수정하면 되기 때문에 유연성을 가진다.

     

    우리의 스프링 프레임워크에서는 위 예시의 설정클래스(Config 클래스) 처럼 생성자나 세터메서드를 이용해서 의존성을 주입할 필요가 없다. 스프링은 주입대상 객체가 빈 객체로 등록만 되어있다면 스프링 컨테이너가 객체를 관리하게 되면서 의존 자동 주입의 기능을 이용할 수 있다. (스프링이 알아서 의존 객체를 찾아서 주입한다.)

    스프링이 최고야

    의존 자동 주입을 이용 하려면 어찌하나요???

    @Autowired 애노테이션을 이용할 수 있다.

    이 애노테이션은 3가지 위치에서 사용이 가능하다.

     

    1. Field를 통한 의존성 자동 주입

    public class MemberService {
    
      // field를 통한 의존 자동 주입
      @Autowired
      private MemberRepository memberRepository;
    
      public void register(Member member) {
      memberRepository.insert(member);
      }
    }

    위 코드는 @Autowired를 field에 적용시켜 의존성을 자동 주입받고 있다. MemberRepository 타입의 빈 객체를 찾아서 memberRepository 필드에 할당한다. 가장 간단하다.

     

    2. 생성자를 통한 의존성 자동 주입

    public class MemberService {
    
      private final MemberRepository memberRepository;
    
      // 생성자를 통한 의존 자동 주입
      @Autowired
      public MemberService(MemberRepository memberRepository) {
      this.memberRepository = memberRepository;
      }
    
      public void register(Member member) {
      memberRepository.insert(member);
      }
    }
    

     이렇게 생성자에 @Autowired 애노테이션을 붙여 의존 자동 주입을 받을 수 있다. spring 4.3 버전부터는 오직 하나의 생정자를 가지고 있다면 @Autowired 애노테이션을 생략할 수도 있다.

     

    3. 세터메서드를 통한 의존성 자동 주입

    public class MemberService {
    
      private MemberRepository memberRepository;
    
      // setter 메서드 통한 의존 자동 주입
      @Autowired
      public void setMemberRepository(MemberRepository memberRepository) {
      this.memberRepository = memberRepository;
      }
    
      public void register(Member member) {
      memberRepository.insert(member);
      }
    }

    또는 세터메서드를 통해 의존하고 있는 객체를 자동 주입(Inject) 받을 수도 있다. 스프링은 해당 메서드를 호출하면서 메서드 파라미터 타입(MemberRepository)에 해당하는 빈 객체를 찾아 인자로 주입하는 것.

     

    field 자동 주입 vs 생성자 자동 주입 vs 세터 메서드 자동 주입

    이중에서 field를 통한 자동 주입은 가능한 피하는게 좋다고 한다.

    field 자동 주입은 코드량은 줄지만 DI 컨테이너에게 지나치게 의존적이라서 단위테스트시, 스프링 설정을 읽고 모든 빈 설정이 되어야만 테스트를 할 수있다.

    또한 생성자와 세터 메서드에 비해서 의존관계를 한 눈에 알아보기가 매우 힘들다.

    필수 또는 불변 프로퍼티 DI 라면 final 제어자를 이용하는 생성자 자동 주입을 사용하고 선택적이고 가변 프로퍼티 DI라면 세터 메소드 자동 주입을 사용해서 보다 정확하게 의존관계를 설명해주면 좋을 듯 하다!

     

    반응형

    댓글

Designed by Tistory.