IOC(제어의 역전, Inversion Of Control)
객체의 생성과 관리 권한을 개발자가 아닌 Spring 컨테이너가 담당하는 것을 말한다. 기본적으로 개발자가 객체를 직접 생성하고 관리했지만, Spring에서는 컨테이너가 객체 생성, 주입, 소멸을 관리한다.
DI(의존성 주입, Dependency Injection)
Spring이 객체 간의 의존성을 자동으로 주입해주는 것을 의미. 한 객체가 다른 객체를 사용할 때, 해당 객체를 직접 생성하지 않고 Spring이 주입해주는 방식이다. IOC를 구현하는 방식 중 하나이다.
예시) IOC / DI
//개발자가 직접 관리
// Service 인터페이스
public interface MyService {
void doSomething();
}
// Repository 인터페이스
public interface MyRepository {
void queryDatabase();
}
// Service 구현체
public class MyServiceImpl implements MyService {
private MyRepository myRepository;
// 의존성 주입
public MyServiceImpl(MyRepository myRepository) {
this.myRepository = myRepository;
}
@Override
public void doSomething() {
System.out.println("서비스 작업 실행");
myRepository.queryDatabase();
}
}
// Repository 구현체
public class MyRepositoryImpl implements MyRepository {
@Override
public void queryDatabase() {
System.out.println("데이터베이스 쿼리 실행");
}
}
public class MyApp {
public static void main(String[] args) {
MyRepository repo = new MyRepositoryImpl();
// MyRepository repo2 = new MyRepositoryImplV2();
MyService myService = new MyServiceImpl(repo);
// MyService myService2 = new MyServiceImpl(repo2);
myService.doSomething();
}
}
// 새로운 Repository 구현체
public class MyRepositoryImplV2 implements MyRepository {
@Override
public void queryDatabase() {
System.out.println("데이터베이스 쿼리 실행 V2");
}
}
- 객체 간의 강한 결합을 유발한다.
- 새로운 Service나 Repository가 생긴다면 클라이언트 측 코드에 영향이 생긴다.
// Spring Container가 관리(Ioc, DI)
// Service 구현체
@Service
public class MyIocService implements MyService {
private final MyRepository myRepository;
// 생성자 주입(DI 적용)
@Autowired
public MyIocService(MyRepository myRepository) {
this.myRepository = myRepository;
}
@Override
public void doSomething() {
System.out.println("IOC 서비스 작업 실행");
myRepository.queryDatabase();
}
}
// Repository 구현체
@Repository
public class MyIocRepository implements MyRepository {
@Override
public void queryDatabase() {
// 데이터베이스와 상호작용
System.out.println("IOC 데이터베이스 쿼리 실행");
}
}
// Spring Container 관리(IoC 적용)
@ComponentScan(basePackages = "com.example")
public class MyIocApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyIocApp.class);
// Service 빈을 가져와서 실행
MyService service = context.getBean(MyService.class);
service.doSomething();
}
}
// 새로운 Repository 구현체
@Repository
public class MyIocRepositoryV2 implements MyRepository {
@Override
public void queryDatabase() {
// 데이터베이스와 상호작용
System.out.println("IOC 데이터베이스 쿼리 실행 V2");
}
}
- 구현 코드가 변경되어도 클라이언트의 코드에는 영향이 없다.
- 다른 구현체를 구현하여 Bean으로 등록하면 자유롭게 변경이 가능하다.
- 위 예시 코드는 @Repository로 등록된 빈이 중복되어 충돌이 발생
- 의존성 주입(DI), 제어의 역전(IOC)을 통해 객체 간의 결합도를 낮추고 유연한 설계가 가능해진다.
정리
- IoC는 객체의 제어권을 개발자가 아닌 Spring 컨테이너에게 넘기는 개념으로, Spring이 객체 생성과 관리를 담당한다.
- DI는 Spring이 객체 간의 의존성을 자동으로 주입해주는 기법이다.
- 의존관계 주입은 객체 간의 결합도를 낮추고 코드의 유연성과 테스트 가능성을 높여준다.
@Configuration // 이 클래스가 Spring 설정 클래스임을 표시
@ComponentScan(basePackages = "com.example") // 컴포넌트 스캔을 통해 해당 패키지 내의 빈을 등록
public class AppConfig {
public static void main(String[] args) {
// ApplicationContext가 Spring IoC 컨테이너를 만들고, 그 안에서 객체를 관리
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Spring 컨테이너에서 MyService 빈을 찾아서 가져옴
MyService service = context.getBean(MyService.class);
service.doSomething(); // MyService가 의존하는 MyRepository가 자동으로 주입됨
}
}
이 과정에서 일어나는 현상
- @Configuration: AppConfig 클래스가 Spring 설정 클래스임을 나타냅니다. 이 클래스는 Spring IoC 컨테이너의 설정을 담당한다.
- @ComponentScan: com.example 패키지 내에서 @Component, @Service, @Repository와 같은 애노테이션을 붙인 클래스를 찾아서 자동으로 빈으로 등록한다.
- 빈 등록 및 의존성 주입: Spring은 @Autowired 애노테이션을 통해 자동으로 의존성 주입을 처리한다. MyService는 MyRepository에 의존하고 있는데, Spring이 MyRepository의 구현체인 MyRepositoryImpl을 찾아서 주입해준다.
- ApplicationContext: Spring 컨테이너를 초기화하고, 애플리케이션에서 필요한 빈을 가져올 수 있는 IoC 컨테이너 역할을 한다. context.getBean(MyService.class)로 Spring이 관리하는 MyService 객체를 가져온다.
정리
1. 기존 자바에서 (수동 DI, 클라이언트 클래스에서 직접 관리)
- 클라이언트 클래스에서 직접 객체를 생성하고, 의존성도 직접 주입해야 했다.
- 예를 들어, MyService가 MyRepository를 사용하려면, MyService 클래스에서 new MyRepositoryImpl()을 사용해서 직접 객체를 생성하고 주입해야 했다.
- 클라이언트 클래스가 객체의 생명 주기와 의존성 관리까지 전부 책임졌다.
2. Spring에서 (자동 DI, IoC 컨테이너가 관리)
- Spring은 IoC 컨테이너를 사용하여 객체의 생성, 관리, 의존성 주입을 자동으로 처리한다.
- 클라이언트 클래스는 Spring이 관리하는 빈(객체)을 가져와서 사용하고, 의존성 주입도 자동으로 이루어진다.
- 클라이언트 클래스는 객체 생성에 신경 쓸 필요 없이 Spring이 필요한 의존성 객체를 자동으로 주입한다.
이걸 간단하게 한 줄로 정리하면
그냥 IOC와 DI를 정리하면 원래 자바에서는 클라이언트 클래스 코드 개발자가 직접 인스턴스화 해주고 주입해주고 그랬는데 Spring은 이걸 클라이언트 클래스에서 자동으로 해준다.
'Back-End > Spring' 카테고리의 다른 글
| Spring Valid (1) | 2024.12.08 |
|---|---|
| Spring Bean 등록 (0) | 2024.12.08 |
| Spring Container와 Spring Bean (0) | 2024.12.06 |
| 객체 지향 설계(SOLID 원칙) (1) | 2024.12.06 |
| Spring DI(의존성 주입)에 대해서 (1) | 2024.12.01 |