waveofmymind
기록하는 습관
waveofmymind
전체 방문자
오늘
어제
  • 분류 전체보기 (124)
    • 📝 정리 (5)
    • 🌊TIL (9)
    • 💻CS (1)
      • 자료구조 (1)
    • 📙Language (9)
      • ☕Java (6)
      • 🤖Kotlin (3)
    • 🍃Spring (28)
    • 👨🏻‍💻알고리즘 (67)
      • 프로그래머스 (59)
      • 백준 (3)
    • 👷DevOps (4)
      • 🐳Docker (2)
      • 🤵Jenkins (1)

블로그 메뉴

  • 홈
  • Spring
  • Java
  • 알고리즘

공지사항

인기 글

태그

  • 트랜잭션 전파
  • 힙
  • 챗GPT
  • 트랜잭션
  • Spring Security
  • 스프링 부트
  • resultset
  • kotest
  • mybatis
  • spring
  • sql
  • Open AI
  • 통합테스트
  • 스택
  • CORS
  • spring boot
  • chat GPT
  • Connection
  • 스프링
  • kotlin
  • BFS
  • 완전탐색
  • JDBC
  • 코틀린
  • AOP
  • 스프링 시큐리티
  • 다이나믹 프로그래밍
  • LeetCode
  • til
  • SpringAOP

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
waveofmymind

기록하는 습관

[Spring] IoC와 DI (1/2)
🍃Spring

[Spring] IoC와 DI (1/2)

2023. 5. 27. 12:33

Inversion of Control

  • 제어의 역전이라고 한다.
  • 스프링 애플리케이션에서 스프링 빈의 생성과 의존관계 설정, 사용 및 제거 등의 작업을 애플리케이션 코드가 아닌 스프링 컨테이너가 담당한다.
  • 이를 스프링 컨테이너가 코드 대신 빈에 대한 제어권을 갖고 있다고 해서 IoC라고 부른다.
  • 스프링 컨테이너를 IoC 컨테이너라고 부르기도 한다.

IoC 컨테이너

  • 스프링에서 IoC를 담당하는 컨테이너를 빈 팩토리, DI 컨테이너, Application Context라고 부른다.
  • 빈(오브젝트)의 생성과 빈 사이의 런타임 관계를 설정하는 DI의 관점에서 컨테이너를 빈 팩토리 또는 DI 컨테이너라고 부른다.
  • 그러나 스프링 컨테이너는 단순히 DI작업보다 더 많은 작업을 하는데, DI를 위한 빈 팩토리에 여러가지 기능을 추가한 것을 Application Context라고 한다.
  • 정리하면, Application Context는 그 자체로 IoC와 DI 기능 뿐만 아니라 그 이상의 기능을 가지고 있다.

빈 팩토리와 Application Context

빈 팩토리

  • 스프링 컨테이너의 최상위 인터페이스
  • 스프링 빈을 관리하고 조회하는 역할을 한다.
  • getBean() 메서드가 대표적이다.

ApplicationContext

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, 
		HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, 
				ResourcePatternResolver {}
  • 빈 팩토리를 상속한 만큼, 빈 팩토리의 기능을 모두 제공한다.
  • 위에서 extends한 인터페이스는 모두 빈 팩토리 인터페이스의 서브 인터페이스이며, 빈 팩토리에 없는 추가 기능을 제공한다. 즉, 애플리케이션은 이를 혼합해서 다음과 같은 기능을 제공한다.
    • 메시지 소스를 활용한 국제화 기능
      • 한국에서 들어오면 한국어로, 영미권에서 들어오면 영어로
    • 환경 변수
      • 로컬, 개발, 운영 등을 구분해서 처리한다.
    • 애플리케이션 이벤트
      • 이벤트를 발행하고 구독하는 모델을 편리하게 지원
    • 편리한 리소스 조회
      • 파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회한다.

설정 메타 정보

IoC 컨테이너의 가장 기초적인 역할은 오브젝트를 생성하고, 이를 관리하는 것이다.

이 때, 스프링 컨테이너가 관리하는 오브젝트를 빈이라 부른다.

설정 메타 정보는 이 빈을 어떻게 만들고 어떻게 동작하게 할 것인가에 관한 정보이다.

스프링 컨테이너는 자바 코드, XML, Groovy 등 다양한 형식의 설정 정보를 받아들일 수 있도록 유연하게 설계되어있다.

어노테이션 기반의 자바 설정

@Configuration
public class AppConfig {

		@Bean
		public MemberService memberService() {
				return new MemberServiceImpl(memberRepository());
		}
}
  • @Configuration: 1개 이상의 빈을 제공하는 클래스의 경우 반드시 명시해야함
  • @Bean: 클래스를 빈으로 등록할 때 사용한다.

XML 기반의 스프링 빈 설정

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://
www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="memberService" class="hello.core.member.MemberServiceImpl">
			 <constructor-arg name="memberRepository" ref="memberRepository"/>
	 </bean>
</beans>
  • 형식이 다를 뿐, 자바 코드로 된 설정 파일과 비슷하다.
  • 최근에는 잘 사용하지 않는다.

스프링 빈 설정 메타 정보 - BeanDefinition

  • 스프링은 이런 다양한 형식을 지원하기 위해 BeanDefinition이라는 추상화가 존재한다.
  • 자바 코드를 읽어 BeanDefinition을, XML을 읽어 BeanDefinition을 만든다. 그렇기 때문에 스프링 컨테이너는 자바 코드, XML을 구분할 필요 없이 BeanDefinition만 알면 된다.
  • 이를 빈 설정 메타 정보라고 하는데, @Bean 과 <bean> 당 각각 하나씩 메타 정보가 생성된다.

  • AnnotationConfigApplicationContext는 AnnotatedBeanDefinitionReader를 사용해서 AppConfig.class를 읽고 BeanDefinition을 생성한다.
  • GenericXmlApplicationContext는 XmlBeanDefinitionReader를 사용해서 appConfig.xml 설정 정보를 읽고 BeanDefinition을 생성한다.

Dependency Injection - 의존 관계 주입

의존관계란?

"A가 B를 의존한다" 는 추상적인 표현이지만, 토비의 스프링에서는 "의존 대상 B가 변하면, 그것이 A에 영향을 미친다" 라고 한다. 

즉, B의 기능이 추가되거나 변경되면 그 영향이 A에 미치는 것이다.

class BurgerChef {
    private HamBurgerRecipe hamBurgerRecipe;

    public BurgerChef() {
        hamBurgerRecipe = new HamBurgerRecipe();        
    }
}

햄버거 레시피가 변하게 되었을때, 변화된 레시피에 따라서 BurgerChef 클래스를 수정해야한다.

레시피의 변화가 요리사의 행위에 영향을 미쳤기 때문에 요리사는 레시피에 의존한다고 할 수 있다.

 

Dependency를 인터페이스로 추상화

위 예제에서, BurgerChef는 HamburgerRecipe만 의존할 수 있는 구조로 되어있다.

더 다양한 햄버거 레시피를 의존할 수 있게 구현하려면, 인터페이스로 추상화해야 한다.

class BurgerChef {
    private BurgerRecipe burgerRecipe;

    public BurgerChef() {
        burgerRecipe = new HamBurgerRecipe();
        //burgerRecipe = new CheeseBurgerRecipe();
        //burgerRecipe = new ChickenBurgerRecipe();
    }
}

interface BugerRecipe {
    newBurger();
} 

class HamBurgerRecipe implements BurgerRecipe {
    public Burger newBurger() {
        return new HamBerger();
    }
}

이제 더 다양한 버거 레시피에 의존할 수 있는 BurgerChef가 되었다.

이처럼 의존 관계를 인터페이스로 추상화하게 되면, 더 다양한 의존 관계를 맺을 수 있고, 실제 구현 클래스와의 관계가 느슨해지면 결합도가 낮아진다.

그래서 결국 DI는?

위 코드에서는 BurgerChef 내부적으로 의존관계인 BurgerRecipe가 어떤 값을 가질지 직접 정하고 있다.

이때 DI는 어떤 햄버거 레시피를 만들 지는 버거 가게 사장이 정하는 상황이라고 할 수 있다. 즉, BurgerChef가 의존하고 있는 BurgerRecipe를 외부에서 결정하고 주입하는 것이다.

class BurgerChef {
    private BurgerRecipe burgerRecipe;

    public BurgerChef(BurgerRecipe bugerRecipe) {
        this.burgerRecipe = bugerRecipe;
    }
}

//의존관계를 외부에서 주입 -> DI
new BurgerChef(new HamBurgerRecipe());
new BurgerChef(new CheeseBurgerRecipe());
new BurgerChef(new ChickenBurgerRecipe());

이처럼 의존관계를 외부에서 결정하는 것을 DI(의존 관계 주입)이라고 한다.

스프링에서는 외부의 대상이 IoC 컨테이너가 되어, 빈을 알아서 주입해준다.

 

'🍃Spring' 카테고리의 다른 글

[Spring] 스프링 부트에서 Chat GPT API 사용해보기  (0) 2023.05.30
[Spring] IoC와 DI (2/2)  (0) 2023.05.29
[Spring] 스프링 빈 스코프 (2/2)  (0) 2023.05.27
[Spring] 스프링 빈 (1/2)  (0) 2023.05.26
[Spring] 테스트 클렌징시 deleteAll()을 사용할 때의 주의점  (0) 2023.05.13
    '🍃Spring' 카테고리의 다른 글
    • [Spring] 스프링 부트에서 Chat GPT API 사용해보기
    • [Spring] IoC와 DI (2/2)
    • [Spring] 스프링 빈 스코프 (2/2)
    • [Spring] 스프링 빈 (1/2)
    waveofmymind
    waveofmymind

    티스토리툴바