
1️⃣ DI (Dependency Injection)
DI (Dependecy Injection) 는 "의존성 주입" 이라는 뜻이다.
저번에 공부했던 SOLID 에 등장한 OCP, DIP 등을 지킬 수 있도록 스프링이 지원해주는 기능이다.
즉, new 연산자를 통해 직접 구현 객체를 생성하는 것이 아닌, 외부에서 객체를 생성한 뒤 주입시켜주는 방식이다.
여기서 말하는 외부는 스프링 컨테이너를 말한다.
예를 들어 'MemberRepository' 라는 인터페이스가 있다고 하자.
그 아래에 'MemoryMemberRepository', 'JdbcRepository' 등이 구현 객체로 있다.
그렇다면 MemberRespository 를 생성할 때 어떤 객체에 의존하면 될까?
여기서 DI 를 적용하기 위해선 둘 다 아니다.
DIP에 따라 추상화에 의존하고 구체화에 의존하면 안되기 때문이다.
따라서 외부에서 구현 객체를 생성한 뒤 MemberRepository 의 생성자나 setter 를 통해 주입하면 된다.
//MemberService
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
//Memory, Jdbc 중 어느 것이 올지 모른다. 이 클래스는 자신의 기능만 수행하면 된다.
}
// AppConfig
public class AppConfig
public MemberRepository memberRepository(){
return new MemoryMemberRepository;
//return new JdbcMemberRepository;
//부품을 갈아끼우듯 쉽게 바꿀 수 있다.
public MemberService memberService(){
return new MemberServiceImpl(memberRepository);
//의존 관계 설정
}
}
우선 'MemberServiceImpl' 를 보면 'MemberService' 인터페이스의 구현체이다.
여기선 'MemberRepository' 를 의존하는데, new 연산자를 통해 구현체를 생성하지 않고 생성자를 통해 주입받는다.
그 결과 해당 코드를 수정하지 않고도 'MemoryMemberRepository' 를 사용할 것인지, 'JdbcRepository' 를 사용할 것인지 결정할 수 있다. 외부에서 객체를 생성하여 주입하기 때문이다.
여기서 OCP, DIP 의 원칙이 잘 지켜졌다.
- 구현체가 아닌 추상화에 의존한다. (new 연산자가 아닌 생성자, setter 등을 통해 의존 관계 설정)
- 확장에는 개방적이나 변경에는 폐쇄적이다.
2️⃣ IoC (Inversion of Control)
IoC (Inbersion of Control) 은 "제어의 역전" 이라는 뜻으로, 프로그램의 제어권이 개발자가 아닌 외부에서 넘어가는 것을 말한다. 쉽게 말해 위 DI 의 예시에서 'AppConfig' 의 설정에 따라 프로그램의 흐름이 바뀌며, 이를 IoC 라고 한다.
쉽게 말해 개발자가 new 연산자를 통해 구현 객체를 직접 생성하는 것이 아닌, 외부에서 생성된 객체를 주입하는 등 프로그램의 제어권이 역전되었다는 의미이다. 여기서 말하는 외부는 스프링 컨테이너를 말하며, IoC 컨테이너라고도 한다.
스프링에서는 객체들이 'Bean' 이라는 개념으로 사용되는데, Bean들은 스프링 컨테이너에 등록되어 프로그램이 실행됨에 따라 필요한 시점에서 생성되고 소멸되며 자동적으로 관리된다.
따라서 IoC 를 통해 객체 간의 관계를 쉽게 관리할 수 있고, 코드가 깔끔해지며 변경과 확장에도 용이하게 된다.
@Configuration
public class AppConfig{
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository;
}
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository);
}
}
@Configuration 과 @Bean 과 관련된 스프링 컨테이너는 다음에 자세히 다뤄보겠다.
참고 : 인프런 김영한님 - 스프링 핵심 원리 기본편

1️⃣ DI (Dependency Injection)
DI (Dependecy Injection) 는 "의존성 주입" 이라는 뜻이다.
저번에 공부했던 SOLID 에 등장한 OCP, DIP 등을 지킬 수 있도록 스프링이 지원해주는 기능이다.
즉, new 연산자를 통해 직접 구현 객체를 생성하는 것이 아닌, 외부에서 객체를 생성한 뒤 주입시켜주는 방식이다.
여기서 말하는 외부는 스프링 컨테이너를 말한다.
예를 들어 'MemberRepository' 라는 인터페이스가 있다고 하자.
그 아래에 'MemoryMemberRepository', 'JdbcRepository' 등이 구현 객체로 있다.
그렇다면 MemberRespository 를 생성할 때 어떤 객체에 의존하면 될까?
여기서 DI 를 적용하기 위해선 둘 다 아니다.
DIP에 따라 추상화에 의존하고 구체화에 의존하면 안되기 때문이다.
따라서 외부에서 구현 객체를 생성한 뒤 MemberRepository 의 생성자나 setter 를 통해 주입하면 된다.
//MemberService
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
//Memory, Jdbc 중 어느 것이 올지 모른다. 이 클래스는 자신의 기능만 수행하면 된다.
}
// AppConfig
public class AppConfig
public MemberRepository memberRepository(){
return new MemoryMemberRepository;
//return new JdbcMemberRepository;
//부품을 갈아끼우듯 쉽게 바꿀 수 있다.
public MemberService memberService(){
return new MemberServiceImpl(memberRepository);
//의존 관계 설정
}
}
우선 'MemberServiceImpl' 를 보면 'MemberService' 인터페이스의 구현체이다.
여기선 'MemberRepository' 를 의존하는데, new 연산자를 통해 구현체를 생성하지 않고 생성자를 통해 주입받는다.
그 결과 해당 코드를 수정하지 않고도 'MemoryMemberRepository' 를 사용할 것인지, 'JdbcRepository' 를 사용할 것인지 결정할 수 있다. 외부에서 객체를 생성하여 주입하기 때문이다.
여기서 OCP, DIP 의 원칙이 잘 지켜졌다.
- 구현체가 아닌 추상화에 의존한다. (new 연산자가 아닌 생성자, setter 등을 통해 의존 관계 설정)
- 확장에는 개방적이나 변경에는 폐쇄적이다.
2️⃣ IoC (Inversion of Control)
IoC (Inbersion of Control) 은 "제어의 역전" 이라는 뜻으로, 프로그램의 제어권이 개발자가 아닌 외부에서 넘어가는 것을 말한다. 쉽게 말해 위 DI 의 예시에서 'AppConfig' 의 설정에 따라 프로그램의 흐름이 바뀌며, 이를 IoC 라고 한다.
쉽게 말해 개발자가 new 연산자를 통해 구현 객체를 직접 생성하는 것이 아닌, 외부에서 생성된 객체를 주입하는 등 프로그램의 제어권이 역전되었다는 의미이다. 여기서 말하는 외부는 스프링 컨테이너를 말하며, IoC 컨테이너라고도 한다.
스프링에서는 객체들이 'Bean' 이라는 개념으로 사용되는데, Bean들은 스프링 컨테이너에 등록되어 프로그램이 실행됨에 따라 필요한 시점에서 생성되고 소멸되며 자동적으로 관리된다.
따라서 IoC 를 통해 객체 간의 관계를 쉽게 관리할 수 있고, 코드가 깔끔해지며 변경과 확장에도 용이하게 된다.
@Configuration
public class AppConfig{
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository;
}
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository);
}
}
@Configuration 과 @Bean 과 관련된 스프링 컨테이너는 다음에 자세히 다뤄보겠다.
참고 : 인프런 김영한님 - 스프링 핵심 원리 기본편