public class OrderServiceImpl implements OrderService {
//private DiscountPolicy discountPolicy = new FixDiscountPolicy();
private DiscountPolicy discountPolicy = new RateDiscountPolicy(); ⇒ 남배우는 공연도 해야하고 동시에 여배우를 직접 초빙해야하는 다양한 책임을 가지게 된다.AppConfig의 등장Config)하기 위해, 구현 객체를 생성하고 연결하는 책임을 가지는 별도의 설정 클래스를 만들자MemberServiceImpl 변경전
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
MemberServiceImpl 변경 후public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
}
MemberRepository의 구현체가 무엇이 들어갈지를 AppConfig의 생성자를 통해 결정한다.MemoryMemberRepository는 인터페이스인 MemberRepository 만 참조,구현체는 없다. ⇒ 인터페이스에만 의존
AppConfigpublic class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(new MemoryMemberRepository(), new RateDiscountPolicy());
}
}

1. AppConfig 는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
- MemberServiceImpl
- MemoryMemberRepository
- OrderServiceImpl
- FixDiscountPolicy
2. AppConfig 는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해 주입한다.
- MemberServiceImpl →MemoryMemberRepository
- OrderServiceImpl → MemoryMemberRepository , FixDiscountPolicy
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
MemberServiceImpl 은 MemoryMemberRepository 를 직접 의존하지 않는다.MemberRepository (인터페이스)만을 의존한다.MemberServiceImpl 의 생성자를 통해서 어떤 구현 객체를 주입할지는 오직 외부(AppConfig)결정**AppConfig에게 넘기고 MemberServiceImpl 는 실행에만 집중**
MemberServiceImpl 이 MemoryMemberRepository 를 생성하였음AppConfig 가 MemoryMemberRepository의 생성과 연결을 담당한다.MemberServiceImpl 은 MemberRepository 인 추상(인터페이스)에만 의존
AppConfig 객체는 MemoryMemberRepository 객체를 생성하고 그 참조값을 MemberServiceImpl 을 생성하면서 생성자로 전달한다.MemberServiceImpl 입장에서 보면 의존관계를 마치 외부에서 주입해주는것 같다고 해서FixDiscountPolicy → RateDiscountPolicy**AppConfig****AppConfig** 의 등장으로 사용 영역과 객체를 생성하고 구성(Configuration)하는 영역으로 분리됨
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
private MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
private DiscountPolicy discountPolicy() {
**// return new FixDiscountPolicy();
return new RateDiscountPolicy();**
}
}
**AppConfig** 만 변경하면 된다.AppConfig 가 담당AppConfig와 생성자 주입을 통해 객체 인스턴스를 생성해서 클라이언트 코드에 의존관계를 주입했다.AppConfig 가 의존 관계를 FixDiscountPolicy → RateDiscountPolicy 로 변경해서 주입AppConfig가 등장한 이후에는구현객체 → 자신의 로직을 실행하는 역할
AppConfig→ 프로그램의 제어 흐름 역할
⇒ 이렇듯 프로그램의 제어 흐름을 직접 제어하는 것이 아닌 외부에서 관리하는 것을 IoC라 한다.

import 만 보고 의존 관계를 판단.
AppConfig 처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것AppConfig 를 바꾸기**@Configuration**
public class AppConfig {
**@Bean**
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
**@Bean**
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
**@Bean**
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
**@Bean**
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
public class MemberApp {
public static void main(String[] args){
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
**ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);**
Member member = new Member(1L, "james", Grade.VIP);
memberService.join(member);
System.out.println("find member : "+member);
System.out.println("memberService.findById(1L) = " + memberService.findMember(1L));
}
}
public class OrderApp {
public static void main(String[] args){
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
// OrderService orderService = appConfig.orderService();
**ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);**
Member member = new Member(1L, "james", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(1L, "toy", 2000);
System.out.println(order);
System.out.println(order.calculatePrice());
}
}
\
ApplicationContext를 스프링 컨테이너라 한다.
기존에는
AppConfig를 사용해서 직접 객체를 생성하고 의존성 주입을 했지만AppConfig를 사용해서 직접 조회함이제는
applicationContext.getBean()메서드를 사용해 찾을 수 있다.스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성)정보로 사용한다.
@Bean이 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.
스프링 빈은 이 붙은 메서드의 명을 스프링 빈의 이름으로 사용한다.