IOC(제어의 역전, Inversion Of Control)
객체의 생성과 관리 권한을 개발자가 아닌 Spring 컨테이너가 담당하는 것을 말한다. 기본적으로 개발자가 객체를 직접 생성하고 관리했지만, Spring에서는 컨테이너가 객체 생성, 주입, 소멸을 관리한다.


DI(의존성 주입, Dependency Injection)
Spring이 객체 간의 의존성을 자동으로 주입해주는 것을 의미한다. 한 객체가 다른 객체를 사용할 때, 해당 객체를 직접 생성하지 않고 Spring이 주입해주는 방식이다. IOC를 구현하는 방식 중 하나이다.
DI의 역할

셰프가 요리를 만들 때 필요한 재료(Bean)를 자동으로 요리사에게 가져다주는 과정

요리사(개발자)는 재료를 찾을 필요 없이, Chef가 알아서 제공해준다.
개발자가 직접 관리
// 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 구현체
@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/DI