공부함

ApplicationContext 본문

스프링

ApplicationContext

찌땀 2024. 8. 28. 22:33

출처

김영한님 스프링 핵심 원리 기본편 강의

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

 

스프링 핵심 원리 - 기본편 강의 | 김영한 - 인프런

김영한 | 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보

www.inflearn.com

 

스프링 컨테이너가 필요한 이유

스프링 컨테이너가 무엇인지 알아보기 전에 먼저 스프링 컨테이너가 왜 필요한지 알아보자. 

public class OrderServiceImpl implements OrderService {
    // private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}

위 코드에서 DiscountPolicy를 FixDisCountPolicy에서 RateDiscountPolicy로 바꾸자 클라이언트 코드에 변경이 발생했다.

OrderServiceImpl은 사실 인터페이스인 DiscountPolicy와 구현체인 FixDiscountPolicy 모두에 의존하고 있는 것이다. 

따라서 OrderServiceImpl이 인터페이스에만 의존하게 하려면 이렇게 수정해야 한다. 

public class OrderServiceImpl implements OrderService {
    private final DiscountPolicy discountPolicy;
}

확실히 인터페이스에만 의존하고 있지만 구현체가 없어 실행이 안된다. 

따라서 이쁜 객체지향적 설계를 하면서 코드를 실행도 하고 싶다면 누군가가 구현체를 대신 생성하고 주입해줘야 한다. 

 

public class AppConfig {
     public MemberService memberService() {
     	return new MemberServiceImpl(new MemoryMemberRepository());
     }
     
     public OrderService orderService() {
     	return new OrderServiceImpl(
     		new MemoryMemberRepository(),
     		new FixDiscountPolicy());
     }
}

그 누군가가 AppConfig이다. AppConfig에서는 구현체를 선택하고 주입해준다. 

public class MemberServiceImpl implements MemberService {
 	 private final MemberRepository memberRepository;
    
     public MemberServiceImpl(MemberRepository memberRepository) {
     	this.memberRepository = memberRepository;
     }

	// 이하생략
}

MemberServiceImpl에서는 생성자를 통해 구현체를 주입받는다.

구현체 선택, 연결에 관한 책임 없이 본인의 비즈니스 로직만 책임진다. 

 

 

IOC와 DI

AppConfig를 통해 IOC와 DI가 발생한다.

IOC 의존관계 역전

구현체는 자신의 로직만 실행하고 제어 흐름은 AppConfig가 결정한다. 

DI 의존성 주입

런타임에 구현체가 생성되고 클라이언트와 서버의 의존관계가 결정된다. 

 

AppConfig를 따라서 IOC 컨테이너 또는 DI 컨테이너라고 할 수 있다. 

 

@Configuration, @Bean을 사용해 스프링을 도입할 수 있다. 

즉 스프링에서 객체 생성, 관리, 의존관계 주입 등의 역할을 하는 것이 스프링 컨테이너이다. 

 

ApplicationContext

  • 스프링 컨테이너는 스프링 빈, 관리 조회의 역할을 한다. 
    • 스프링 컨테이너는 빈 저장소를 Map의 형태로 갖는다. (Key : 빈이름 - Value : 빈 객체)
  • BeanFactory는 스프링 컨테이너의 최상위 인터페이스다. 
  • ApplicationContext는 BeanFactory를 상속한다. BeanFactory + 부가기능(국제화, 환경변수 관리 등..)이다. 
  • ApplicationContext는 xml, Java 클래스 등 다양한 형태의 구현체를 만들 수 있다. 

다양한 설정 정보 형식 지원 

ApplicationContext에 설정 정보를 등록해 준다. 설정 정보는 애노테이션 기반 java 클래스, xml 파일 등 다양한 형식을 지원한다.

ApplicationContext ac = new ApplicationContext(AppConfig.class);
ApplicationContext ac = new ApplicationContext(appConfig.xml);

이렇게 다양한 형식을 지원할 수 있는 이유는 BeanDefinition 덕분이다. 

설정 정보 파일의 형식에 관계없이 스프링 컨테이너는 BeanDefiniton에 의존한다. 

애노테이션 기반 java 파일일 경우는 @Bean, xml 파일일 경우는 <Bean> 하나 당 빈 설정 메타 정보인 BeanDefinition이 하나씩 생성된다. 

싱글톤 컨테이너

스프링 컨테이너는 싱글톤 컨테이너다.

즉 스프링 빈을 알아서 싱글톤으로 관리한다. 

 

싱글톤이 되도록 보장하기 위해 @Configuration이 붙은 설정 파일은 스프링이 자체적으로 CGLIB이라는 바이트코드 조작 라이브러리를 사용해 싱글톤을 보장하도록 한다. 

예를 들어 Configuration 파일에서 특정 빈이 여러번 생성될 것 같아도 실제로는 바이트코드 조작에 의해 수정되고 싱글톤이 보장된다.