DI(Dependency Injection) - 의존성 주입
객체를 직접 생성하는게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다. DI를 통해 모듈 간의 결합도가 낮아지고 유연성이 높아진다. 따라서 강한 결합의 문제를 해결할 수 있다. 예제를 통해 알아보자
강한 결합의 예제
1. Contoller1 이 Service1 객체를 생성하여 사용
public class Controller1 {
private final Service1 service1;
public Controller1() {
this.service1 = new Service1();
}
}
2. Service1 이 Repostiroy1 객체를 생성하여 사용
public class Service1 {
private final Repository1 repository1;
public Service1() {
this.repository1 = new Repository1();
}
}
3. Repostiroy1 객체 선언
public class Repository1 { ... }
4. 만약 여기서 Repository의 생성자를 변경하고자 한다면... -> 많은 수정 필요 -> 강한 결합의 문제점
왜 강한 결합일까? 강한 결합의 문제점
Controller 5개가 Service1을 생성하여 사용 중일 때, 만약 Repository1 생성자를 변경하고자 한다면..
Ex) new Repository -> new Repository(id, pw)로 변경하고자 한다면..
-> 모든 Controller와 모든 Service의 코드 변경이 필요하다.

강한 결합 해결방법 - DI(의존성 주입) 예제
"강한 결합" 해결법
1. 각 객체에 대한 객체 생성은 딱 1번만!
2. 생성된 객체를 모든 곳에서 재사용
1. Repository1 클래스 선언 및 객체 생성 → repository1
public class Repository1 { ... }
// 객체 생성
Repository1 repository1 = new Repository1();
2. Service1 클래스 선언 및 객체 생성 (repostiroy1 사용) → service1
Class Service1 {
private final Repository1 repitory1;
// repository1 객체 사용
public Service1(Repository1 repository1) {
// this.repository1 = new Repository1(); -> 강한 결합
this.repository1 = repository1; // 의존성 주입
}
}
// 객체 생성
Service1 service1 = new Service1(repository1);

이런식으로 한번만 선언해서 재사용하게 된다.
3. Contoller1 선언 ( service1 사용)
Class Controller1 {
private final Service1 service1;
// service1 객체 사용
public Controller1(Service1 service1) {
// this.service1 = new Service1(); -> 강한 결합
this.service1 = service1; // 의존성 주입
}
}
4. 만약, Repository1 객체 생성 시 DB 접속 id, pw 를 받아서 DB 접속 시 사용으로 변경된다면..
Ex) new Repository -> new Repository(id, pw)로 변경하고자 한다면..
- 생성자에 DB접속, id, pw 추가
public class Repository1 {
public Repository1(String id, String pw) {
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", id, pw);
}
}
// 객체 생성
String id = "sa";
String pw = "";
Repository1 repository1 = new Repository1(id, pw);
개선 결과
-> Repository1 생성자 변경을 해도 다른 코드를 수정할 필요없이 Repository단의 처음 생성하는 부분만 변경해주면 된다.
===> 결론적으로 느슨한 결합으로 변경되었다.

그림으로 보면 다음과 같다..!
IoC(Inversion of Control) - 제어의 역전
IoC란 직역하면 프로그램 제어의 흐름이 뒤바뀜이라는 뜻이다. 말 그대로 제어의 역전이다 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되도록 흐름이 넘어간 것이다. 스프링에서는 스프링이 모든 의존성 객체들을 만들어주고 필요한 곳에 주입시켜 줌으로써 Bean들은 싱글턴 패턴의 특징을 가지고 제어의 흐름이 사용자가 아닌 스프링에게 컨트롤 되는 것이다.아래 사진을 보면 왼쪽은 강한 결합의 예로 사용자가 생성하여 사용하는 것이지만 오른쪽을 보면 외부에서 생성된 것을 가져와 주입시켜주는 것을 볼 수 있다. 확실히 제어의 흐름이 반대로 가는 것을 쉽게 이해할 수 있다.
일반적으로는 사용자가 자신이 필요한 객체를 생성해서 사용하게 된다.
하지만 IoC의 경우
- 용도에 맞게 필요한 객체를 그냥 가져다 사용한다.
-> DI, 의존성 주입 - 사용할 객체가 어떻게 만들어졌는지 알 필요가 없다.
Bean, IoC Container
Bean
- 스프링이 관리하는 객체
IoC Container
- Bean들을 모아둔 통
- 객체의 생성과 관계설정, 사용, 제거 등의 작업을 수행. 즉, 스프링 프레임워크가 필요한 객체를 생성하여 관리하는 역할을 대신 해주는 것이다.
'Back-end' 카테고리의 다른 글
| [Spring] Unit Test(단위 테스트) 작성의 필요성 (0) | 2021.11.26 |
|---|---|
| [Spring] Transaction(트랜잭션)에 대해 (0) | 2021.11.26 |
| [Java] Java Matcher 클래스(자바 정규 표현식) - 사용법 (0) | 2021.11.20 |
| [Spring] Spring Framework MVC (0) | 2021.11.18 |
| [Spring] @Controller와 @RestController 차이점 (0) | 2021.11.18 |