Spring :: DI & IoC

태그
Java
Spring
날짜
2024/11/12
2 more properties

IoC (Inversion of Control : 제어의 역전)

코드의 흐름이 제3자에게 위임되는 것
public class A { private B b; public A() { b = new B(); } }
Java
복사
A 클래스는 B 필드를 가지고 있고, 생성자 내부에서 직접 생성해(new) 필드를 초기화 하고 있다.
→ 객체의 생명주기나 메소드의 호출을 개발자가 직접 제어하고 있다.
→ 이 흐름을 외부에서 관리한다면?
public class A { @Autowired private B b; // 필드 주입방식 }
Java
복사
B 객체가 Spring Container에서 관리되고 있는 Bean이라면, @Autowired를 통해 객체를 주입받을 수 있다.
→ 개발자가 객체를 직접 제어하지 않고, Spring Container에서 객체를 생성하여 해당 객체를 주입시켜 주었다.
→ 이것이 제어의 역전이다.
객체의 제어를 개발자가 하지않고, Spring에게 위임

IoC가 가지는 장점

역할과 관심을 분리해 응집도를 높이고 결합도를 낮추며, 이에 따라 변경에 유연한 코드를 작성할 수 있다.
프로그램의 진행 흐름과 구체적인 구현을 분리시킬 수 있다.
개발자는 비즈니스 로직에 집중할 수 있다.
객체 간 의존성이 낮아진다.

DI (Dependency Injection : 의존성 주입)

IoC를 구현하기 위해 사용하는 디자인 패턴 중 하나.
이름대로 객체의 의존관계를 외부에서 주입시키는 패턴

DI의 3가지 조건

1.
클래스 모델이나 코드에 런타임 시점의 의존관계가 드러나지 않는다.
a.
그러기 위해서는 인터페이스에만 의존하고 있어야한다.
2.
런타임 시점의 의존관계는 컨테이너 or 팩토리 같은 제3의 존재가 결정한다.
3.
의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 주입해주며 만들어진다.
public class A { private B b; public A() { b = new B(); } }
Java
복사
위 코드는 생성자 내부에서 필드를 초기화 하는 예제이다. 다음과 같은 문제점이 있다.
1.
강한 결합
만약 B 객체의 생성자에 변경이 생긴다면 (기본 생성자 메소드의 로직 변경 등) 모든 A 클래스가 영향을 받는다. → 유연성이 떨어진다.

의존성 주입 방법

1.
생성자 주입 (Constructor Injection)
public class Test { private TestService testService; // 생성자 주입 public Test(TestService testService) { this.testService = testService; } }
Java
복사
가장 권장되는 의존성 주입 방식
final 키워드를 사용할 수 있다.
생성자 주입만 가능하다.
불변성이 보장된다.
NPE가 발생하지 않는다.
2.
수정자 주입 (Setter Injection)
public class Test { private TestService testService; // 수정자 주입 @Autowired public setTestService(TestService testService) { this.testService = testService; } }
Java
복사
NPE가 발생할 수 있다.
final 키워드를 사용할 수 없어, 불변성이 보장되지 않는다.
3.
필드 주입 (Field Injection)
public class Test { // 수정자 주입 @Autowired private TestService testService; }
Java
복사
코드가 간결해진다.
단일 책임 원칙을 위배한다.
final 키워드를 사용할 수 없어, 불변성이 보장되지 않는다.

요약

Spring 문서에 언급되는데, 의존성 주입을 할 때는 생성자 주입 방식을 사용하는 것이 좋다.
불변성이 보장되고, NPE가 방지되는 장점을 갖고, 프레임워크에 의존적이지 않다.