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) 코드를 실행부분과 객체를 생성하는 부분을 분리하기
참고
'Spring' 카테고리의 다른 글
2022-11-25 IoC(제어의 역전), DI(의존관계 주입) - setter메소드를 이용해 객체 생성하기 리뷰 (0) | 2022.11.26 |
---|---|
2022-11-25 IoC(제어의 역전), DI(의존관계 주입) - 생성자를 이용해 객체 생성하기 리뷰 (0) | 2022.11.25 |
2022-11-24 스프링 - IoC(제어의 역전)컨테이너를 이용해 결합도 낮은 코드만들기 (0) | 2022.11.24 |
2022-11-23 스프링 board패키지 리뷰 (0) | 2022.11.24 |
2022-11-23 스프링 customer패키지 리뷰 (0) | 2022.11.24 |
댓글