본문 바로가기
Spring

2022-11-25 [Spring] IoC(제어의 역전), DI(의존관계 주입)에 대해서

by HTT 2022. 11. 25.

IoC컨테이너는 DL과 DI를 제공한다.


DI(Dependency Injection)

 


: 의존성 주입, 즉 개발자가 객체를 직접호출하는 대신, 스프링 컨테이너가 내부에서 설정파일에 등록된 객체를 만들면서 그 객체가 의존하고 있는 모듈(객체)을 직접 생성해서 전달해주는 방식이다.

 

 

DI(Dependency Injection)


: 개발자가 스프링컨테이너로부터 직접 객체를 찾아와서 사용하는 DL과 다르게 Spring컨테이너 내부에서 설정파일에 등록된 객체를 만들면서 그 객체가 의존하고 있는 모듈(객체)을 직접 생성해서 전달해주는 작업까지 처리한다.
ApplicationContext가 생성될 때 자동으로 모든 작업이 처리된다.
=> 이를 위해서 개발자가 설정파일에 생성할 객체와 그 객체가 사용하는 의존모듈을 어떤 방식으로 주입할 것인지 명시해야 한다.

 

  • 두 객체 간의 관계라는 관심사의 분리
  • 두 객체 간의 결합도를 낮춤
  • 객체의 유연성을 높임
  • 테스트 작성을 용이하게 함

 

DL(Dependency Lookup)

 

: 컨테이너가 제공하는 메소드를 통해서 컨테이너 내부에 저장된 객체를 가져오는 작업
  --------------------------------------
                getBean

 

 

의존관계 주입 방법

 

① 생성자를 통해서 주입받는 방법(Constructor Injection)


* 주입받을 클래스에서 객체를 주입받을 수 있도록 생성자가 정의되어 있어야 한다.
* 설정파일(xml)에서 객체를 전달받을 수 있도록 <comstructor-arg>엘리먼트를 이용해서 정의
                                                                                                           -------------------------
                                                                                    <bean>태그 내부에 있어야 한다.
                                                                             매개변수 갯수와 <comstructor-arg>갯수가 동일해야 함

 

 

② setter메소드를 통해서 객체를 주입받는 방식(Property Injection, Setter Injection, 수정자 주입)


* 주입받는 방식을 생성자라 아니라 setter메소드를 통해 전달받도록 설정
* 객체를 주입받는 클래스에는 기본설정인 경우 기본생성자와 setter메소드가 정의되어 있어야 한다.
<Property>엘리먼트를 이용해서 작업

 

 

③ 필드 주입를 통해서 주입받는 방법(Field Injection)

 

* @Autowired를 통해 필드에 바로 주입받는 방법이다.

* 코드가 간결해지는 장점은 있지만 외부에서 접근이 불가능하여 수정이 어렵다.

* DI 프레임워크가 존재하지 않으면 사용할 수 없다.

 

 


 

스프링에서 생성자 주입을 권장(사용해야)하는 이유

 

불변

- 의존 관계 주입은 처음 애플리케이션이 실행될 때 대부분 정해지고 종료 전까지 변경되지 않고 변경되어서는 안된다.
- 수정자 주입 같은 경우에는 이름 메서드를 public으로 열어두어 변경이 가능하기 때문에 적합하지 않다.(누군가 실수로 변경할 수도 있고, 애초에 변경하면 안되는 메서드가 변경할 수 있게 설계하는 것은 좋은 방법이 아니다.
- 생성자 주입 은 객체를 생성할 때 최초로 1번만 호출되고 그 이후에는 다시는 호출되는 일이 없기 때문에 불변하게 설계할 수 있다.
누락

호출했을 때는 NPE(Null Point Exception)이 발생하는데 의존관계 주입 이 누락되었기 때문에 발생한다.생성자 주입 을 사용하면 주입 데이터 누락 시 컴파일 오류가 발생한다.
final 키워드 사용 가능

- 생성자 주입을 사용하면 필드에 final 키워드를 사용할 수 있다.
- 생성자에서 값이 설정되지 않으면 컴파일 시점에서 오류를 확인할 수 있다.
- java: variable (데이터 이름) might not have been initialized
- 생성자 주입을 제외한 나머지 주입 방식은 생성자 이후에 호출되는 형태이므로 final 키워드를 사용할 수 없다.
순환 참조

- 순환 참조를 방지할 수 있다.개발하다보면 여러 컴포넌트 간에 의존성이 생기게 된다(A → B를 참조하고, B → A를 참조).
- 필드 주입과 수정자 주입은 빈이 생성된 후에 참조를 하기 때문에 애플리케이션이 어떠한 오류와 경고 없이 구동된다.실제 코드가 호출될 때까지 문제를 알 수 없다.
생성자를 통해 주입하게되면 BeanCurrentlyInCreationException이 발생하게 된다.

 

 

 


 

 

1) 상위 인터페이스와 구현부를 분리한다. 즉, 상위 인터페이스를 만들어 상속받는다.

2) OCP, DIP개념에 벗어나지 않게 코드를 짠다.

OCP : 정책이나 요구사항이 변경되어도 코드가 수정되면 안 됨!

DIP : 소스는 상위 인터페이스에만 의존할 수 있도록 구현하기!

3) 코드를 실행부분과 객체를 생성하는 부분을 분리하기 

 

 

 

참고

https://mangkyu.tistory.com/125

https://velog.io/@bimilless/%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95

댓글