본문 바로가기
Spring/Spring-detail

DI 의존성 주입 방법에 대해 알아보자

by YoonJong 2022. 10. 26.
728x90

먼저 의존성이란 무엇인지 알아보자.

사용하는 객체 A 와 사용되는 객체 B 가 있다고 예를 들어본다.

아래는 new 키워드를 사용하는 예시이다.

더보기

A는 B 를 사용하기 위해 new 키워드를 이용해 생성하고 B 의 메서드를 사용한다.

( DI 컨테이너에서는 new 키워드를 사용하지 않고, 스프링 프레임워크가 대신한다 )

아래와 같은 형태를 A 는 B 에 의존한다 라고 한다.

class A {
	B b = new B();
    b.methodX();
}

위의 상황에서 설계가 변경되어서 B 클래스에서 C 클래스로 변경하고, methodY 를 호출해야한다고 하면 아래와 같이 코드를 변경해야 한다.

class A {
	C c = new C();
    c.methodY();
}

이러한 방식으로 설계가 변경된다면 10군데든 , 100군데든 모두 찾아서 수정작업을 진행해야 할 것이다.

 

이러한 방법을 효율적으로 하기 위해 인터페이스를 이용한다.

A클래스와 B클래스 , A 클래스와 C 클래스 사이에 인터페이스를 생성한다.

B 클래스와 C 클래스는 생성한 인터페이스를 구현한다.

// I 인터페이스
interface class I {
	methodX();
}
// I 인터페이스를 구현한 B 클래스
class B implements I {
	medthodX() {
     ... 
 	}
}


// I 인터페이스를 구현한 C 클래스
class C implements I {
	medthodX() {
     ... 
 	}
}

위와 같이 가정한다면 A 클래스에서는 아래와 같이 수정할 수 있다.

이는 인터페이스를 참조 받는 유형으로 사용하기 때문에 변수의 이름을 변경하지 않아도 된다.

바퀴를 갈아끼듯이 사용할 수 있다.

// B 래스의 메서드를 사용하고 싶을 때
lass A {
	I i = new B();
    i.methodX();
}
// C 클래스의 메서드를 사용하고 싶을 때
class A {
	I i = new C();
    i.methodX();
}

 

 

DI 컨테이너 인스턴스 생성을 맡기고 관리하는 것을 아래 5가지 규칙을 지키면 보장할 수 있다.

1. 인터페이스를 이용하여 의존성을 만든다.

 - 의존하는 부분에 인터페이스를 사용한다.

 

2. 인스턴스를 명시적으로 생성하지 않는다

 - new 키워드를 사용하지 않는다

 

3. 어노테이션을 클래스에 부여한다.

-  @Component 등을 이용해서 클래스나 메서드를 Bean으로 등록한다.

 

4. 스프링 프레임워크에서 인스턴스를 생성한다.

 - 스프링 프레임워크는 시작할 때 대상의 프로젝트를 컴포넌트 스캔하여 Bean으로 등록한 클래스를 추출하고 인스턴스로 생성한다.

 

5. 인스턴스를 이용하고 싶은 곳에 어노테이션을 부여한다.

 - @Autowired 등을 사용한다.

 

 

DI ( Dependency Injection ) : 의존성 주입

  • 강하게 결합된 클래스들을 분리한다 -> 관심사의 분리
    * 강한결합 : A 클래스 내부에서 B 라는 객체를 직접 생성하고 있을 때, B를 C로 바꾸고 싶다면, A 클래스를 수정해야한다.
  • 결합도를 낮추고 유연성을 확보해준다
  • 테스트 작성을 용이하게 한다.

Spring 은 @AutoWired 어노테이션을 이용해 다양한 의존성주입 방법을 제공한다.

 

의존성 주입 방법으로는 3가지가 있다.

1. 생성자주입 ( 추천방법 )

2. 필드주입 -> Spring에서도 추천하지 않는 방법

3. Setter(수정) 주입


1. 생성자주입

public class MemberService {

    private final MemberRepository memberRepository;
    private final PasswordEncoder passwordEncoder;

	@AutoWired // 생성자가 1개일때는 생략이 가능하다
    public MemberService(MemberRepository memberRepository, PasswordEncoder passwordEncoder) {
        this.memberRepository = memberRepository;
        this.passwordEncoder = passwordEncoder;
    }

 

  • 생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장된다.
  • 의존관계가 설정되지 않으면 객체생성이 불가능하므로, 컴파일 단계에 인지가 가능하다.
  • final 로 선언이 가능하다 -> 불변
  • 테스트 코드에 용이하다

추천하는 이유를 상세히 알아보자

1. 순환참조를 방지

 

A -> B를 참조하고 B -> A 를 참조한다고 가정

계속해서 무한대로 순환하는데, 생성자를 통해주입하고 실행하면 BeanCurrentlyInCreationException 에러가 발생해 

오류를 체크할 수 있다.

@Service
public class AService {    
	// 순환 참조   
	@Autowired    
	private BService bService;     
	
    public void HelloA() {       
		bService.HelloB();    
	}
}
@Service
public class BService {
	// 순환 참조    
	@Autowired    
    private AService aService;     
	
    public void HelloB() {        
	aService.HelloA();    
    }
}

 

2. 불변성 

final 로 선언해서 불변성을 보장할 수 있다. ( 객체가 변할 일이 없다 )

OOP 의 원칙중 OCP(Open Closed Pricipal ) 원리를 지킬 수 있다. - 개방 폐쇄의 원칙

null 의 입력을 방지해주는 역할도 한다.

@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;

2. 필드주입

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private MemberService memberService;

}
  • Spring 에서는 이미 추천하지 공식적으로 추천하지 않는 방식이다.
  • 프레임워크에 의존적이고 객체지향적으로 좋지 않다.
  • 단위테스트를 진행할 경우 의존관계를 가지는 객체를 생성해서 주입할 수 없다.
  • 애플리케이션 코드에서는 사용하지 않으며, 테스트 코드에서만 사용한다.

3. 수정자 주입

@Service
public class UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}
  • 주입받는 객체가 변경될 가능성이 있을 때 사용 -> 거의 없다.
  • SetXXX 메서드를 사용하므로, 어디서든 변경이 가능하다

 

 

 

참고

https://mangkyu.tistory.com/125

 

[Spring] 다양한 의존성 주입 방법과 생성자 주입을 사용해야 하는 이유 - (2/2)

Spring 프레임워크의 핵심 기술 중 하나가 바로 DI(Dependency Injection, 의존성 주입)이다. Spring 프레임워크와 같은 DI 프레임워크를 이용하면 다양한 의존성 주입을 이용하는 방법이 ..

mangkyu.tistory.com

https://dev-coco.tistory.com/70

 

[Spring] 의존성 주입 3가지 방법 - (생성자 주입, Field 주입, Setter 주입)

Spring은 @Autowired 어노테이션을 이용한 다양한 의존성 주입(DI; Dependency Injection) 방법을 제공합니다. 의존성 주입은 필요한 객체를 직접 생성하는 것이 아닌 외부로부터 객체를 받아 사용하는 것입

dev-coco.tistory.com

https://mangkyu.tistory.com/150

 

[Spring] 의존성 주입(Dependency Injection, DI)이란? 및 Spring이 의존성 주입을 지원하는 이유

1. 의존성 주입(Dependency Injection)의 개념과 필요성 [ 의존성 주입(Dependency Injection) 이란? ] Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하고 있는데, 그 중 하나가 의존성 주입(Depen..

mangkyu.tistory.com

 

728x90

댓글