[Spring 기본] Container와 Bean과 조금 더 친해져보자

2022. 10. 13. 16:48·Spring/Spring 기본
728x90
반응형

지난 포스트에서 Container와 Bean 에 대해서 알아볼 수 있었습니다. 이번 포스트에서는 살짝 더 나아가,

Container 안에서 Bean 이 어떤 형태로 관리되고 있는지, 정확히 어떻게 관리되고 있는지 살펴보겠습니다. (약간

의 TMI 같기도..)

 

내용이 조금 복잡하다고 느끼실 수 있는데, 마지막 요약을 보시면서도 한번 더 정리하시면 어느정도 그림이 그려지실 것 같습니다. Bean 을 직접 제어하는 일은 거의 없으니 너무 신경쓰실 필요는 없습니다.

 

 

Application Context

 

ApplicationContext ac = AnnotationConfigApplicationContext(AppConfig.class);

 

이전 포스트에서 Spring 에서 관리해주는 Bean 객체들을 모아두는 공간을 Spring Container 라고 하며, 이를 앱

내에서는 ApplicationContext라고 부른다고 정리하였습니다. 그리고 상단 코드와 같이 Container 를 사용하겠다

고 직접 호출할 수 있습니다.

 

지금까지 객체지향 내용들을 이해하셨다면, ApplicationContext 역시 Interface 역할 객체라는 느낌이 확 오실 것

입니다. 그리고 AnnotationConfigApplicationContext는 이 ApplicationContext 를 구현하는 하나의 방법, 하

나의 구현 객체 입니다. 이 Spring Container에 설정 정보를 처리하는 방법은 정말 다양하기 때문에, 역할과 구현

을 분리해 놓은 모습입니다. 

 

이 ApplicationContext에 대한 대표적인 두 구현 객체입니다. (참고로, 이 구현객체에 대한 지정은 앱에 대한 구성시 스프링이 알아서 어떤 것을 사용중인지 판단 후 지정해주는 것으로 보입니다)

 

Annotation Configuration : 지난 포스트에서 봤던 방법이 Annotation 을 통한 등록 방법입니다. 앱이 실행시점에 @Configuration 이라는 annotation 이 붙은 설정 class 를 통해 Container 내에서 관리해야할 Bean 들을 등록해 놓게 됩니다. 
XML Configuration : XML 문서를 통해서 Bean 들을 등록하는 방법입니다. Annotation 보다 직관성이 떨어지기 때문에 요즘은 잘 사용되지 않는 방법입니다. 

 

스프링 컨테이너에는 스프링 빈 저장소가 있습니다. 빈 이름과 빈 객체를 매핑하여 저장시켜주는 공간으로, 이 공간

에 등재된 빈 들은 앞으로 해당 빈의 주입이 필요한 클라이언트들에게 제공되게 됩니다.

 

스프링 컨테이너와 빈 저장소의 모습

 

 

스프링 컨테이너가 Initialize 되면서 사용하는 방식을 통해 빈 메타 데이터를 형성하게 되는데 (아래 나옵니다), 형성을 마치면 필요한 빈들을 알게 되고, 스프링 빈 저장소에 필요한 빈들을 실제로 저장하는 단계가 진행됩니다.

 

이 때, 스프링에서 빈 저장소에 빈을 생성하는 것과, 이후 의존관계를 주입하는 단계가 나뉘어져 있다는 점을 명심

하면 좋습니다. 지금까지 한 방법, 즉 생성자를 통해서 진행하게 된다면 이 두 과정은 동시에 일어나게 되지만, 원래

는 두 단계가 나뉘어져 있습니다. "갑자기 뭔소리지?" 싶으실 수 있으니, 일단 알아만 두시고, 나중에 더 자세히 살

펴보겠습니다.

 

 

Bean Factory 

 

BeanFactory의 위치에 대한 그림

 

Bean Factory 는 스프링 컨테이너의 최상위 인터페이스이고, 스프링 빈을 관리하고, 조회하는 핵심 코드들이 구성

되어 있는 공간입니다(getBean(), getDividedNames() ... ). 즉, 스프링 컨테이너인 ApplicationContext 는

Bean 을 관리하기 위한 공간이며, 해당 공간에서 사용하는 메인 로직 함수들이 BeanFactory 최상위 인터페이스에

존재한다고 보면 됩니다 (.. BeanFactory나, ApplicationContext 나 모두 Spring Container 입니다)

 

ApplicationContext는 당연히  BeanFactory 의 모든 기능을 상속받아서 사용할 수 있습니다. 위에서 말씀드린 것

처럼 핵심 기능들은 BeanFactory 에서 제공이 되지만, ApplicationContext 역시 빈 관리 측면에서 추가 기능 로직

들이 구현되어 있기에 하나의 객체로 존재하고 있는데, 다음과 같은 내용들이 있다 정도만 알아두시면 될 것 같습니

다(거의 쓸 일 없으실 것..).

 

 

(1) MessageSource

한국어, 영어 등 언어 기능을 지원합니다

 

(2) EnvironmentCapable

로컬(PC), 개발(Test Server), 운영 환경(실제 Production) 등 환경 변수 관련된 변수들에 대한 처리를 도와줍니다

 

(3) ApplcationEventPublisher

이벤트를 발행하고, 구독하는 모델을 편리하게 지원합니다

 

(4) ResourceLoader

내부적으로 편리한 리소스 조회와 특정 파일 같은 외부 리소스들도 편리하게 조회할 수 있도록 도와줍니다.

 

 

어쨌든 우리가 앞으로 빈에 관련되어 사용할 메인 로직들은 대부분 BeanFactory의 핵심 로직들이며, 위와 같은 기

능 로직들을 Application Context가 제공해주게 됩니다 (기능 로직들 관련해서는 추후 기회가 되면 정리해보겠습

니다). 

 

 

 

빈 설정 메타 정보 (Bean Definition)

 

BeanDefinition 형성을 지원하는 다양한 방법

 

위에서 ApplicationContext 를 구현하기 위해서 Annotation을 사용하기도 하고, Xml을 사용하는 방식도 있으며

다양한 방식을 지원한다고 언급하였습니다. 여기서 추상적으로 구현한다고 설명드렸었는데, 이 때 만드는 정보가

바로 빈 설정 메타 정보, 바로 Bean Definition 값입니다.

 

각 설정 파일들을 읽을 때 해당 파일의 방식 (Java : AppConfig.class , XML : appConfig.xml 등등)에 따라

AppliationContext 는 자신의 구현객체를 붙입니다. 

 

---

(구현객체 사진 + Bean Reader 사진) 

---

 

그리고 위 사진과 같이 각 구현 객체에서 사용할 수 있는 BeanDefinitionReader 를 사용해서 Configuration 파일

을 읽고 BeanDefinition을 생성하게 됩니다. (빈 메타정보 형성 이후에 실제 빈 생성이 이루어집니다)

 

사실 여기서도 Spring이 적용한 역할과 구현의 분리를 잘 확인할 수 있습니다. ApplicationContext는 어떤 수단

(Java, XML 등등) 을 사용하든지 Bean Definition 만 만들면 되기 때문에, 자신의 구현객체가 어떤 방식으로

BeanDefinition 을 만들었는지 알 필요가 없는 구조입니다.  

 

 

 

 

 

점점 복잡해지죠..? Spring Container(Application Context)에 빈 저장소가 있다하다가, Spring Container 상위

개념은 Bean Factory 라고 하다가, 이젠 갑자기 Bean Definition 이 저장된다 합니다. 한번 정리해볼게욥.. 

 

 

 

BeanDefinition? Bean 저장소? BeanFactory?

 

 

---

(하단 블로그 그림, 한쪽만)

---

 

Bean Factory 에는 핵심 로직들이 있으며, 이 핵심 로직들을 ApplicationContext 가 상속받고, 추가적인 기능 로

직들을 제공한다고 설명드렸습니다. 이에 따라 ApplicationContext 는 BeanFactory의 공간을 가지고 있고, 추가

적인 기능들을 가지고 있는 위의 그림처럼 이해해볼 수 있습니다.

 

BeanFactory 에는 BeanDefinitionMap과 SingletonObjects 라는 공간 두개가 있다고 정리해볼 수 있습니다.

SingletonObjects 란 공간이 위에서 언급한 Bean 저장소이며, methodName 과 실제 저장하는 bean 객체를 매

핑하여 저장해두는 공간입니다.

 

또한 위에서 ApplicationContext 구현 객체에 붙어 있는 Reader가 읽으면서 형성한 BeanDefinition 객체들은 또

다른 Map 공간에 동일한 methodName 과 매핑되어 저장되는데, 이 공간이 바로 BeanDefinitionMap 입니다.

 

위 그림을 보시니 어느정도 이해가 되시죠...?

 

 

 

Bean Definition 정보들 살펴보기

 

 

@Test
@DisplayName("빈 메타 정보 확인")
void beanDefinitions(){

    String[] beanDefinitionNames = ac.getBeanDefinitionNames();

    for (String beanName : beanDefinitionNames) {
        BeanDefinition beanDefinition = ac.getBeanDefinition(beanName);

        if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
            System.out.println("beanDefinition = " + beanDefinition);
        }
    }
}

Result

beanDefinition = Generic bean: class [com.example.basicprinciple.config.AppSpringConfig$$EnhancerBySpringCGLIB$$727ea2c]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appSpringConfig; factoryMethodName=memberRepository2; initMethodName=null; destroyMethodName=(inferred); defined in com.example.basicprinciple.config.AppSpringConfig
beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appSpringConfig; factoryMethodName=memberService; initMethodName=null; destroyMethodName=(inferred); defined in com.example.basicprinciple.config.AppSpringConfig
beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appSpringConfig; factoryMethodName=discountPolicy2; initMethodName=null; destroyMethodName=(inferred); defined in com.example.basicprinciple.config.AppSpringConfig
beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appSpringConfig; factoryMethodName=orderService; initMethodName=null; destroyMethodName=(inferred); defined in com.example.basicprinciple.config.AppSpringConfig

 

위와 같이 Bean Definition Map 에서 각 BeanDefinition을 찾아서 조회해보면, Result 와 같은 결과들이 출력되는 모습을 확인할 수 있습니다. 저장되어 있는 정보들은 다음 정도와 같다고 생각하면 될 것 같습니다. 

 

BeanClassName : 생성하는 빈의 Class Name
FactoryBeanName : 팩토리 역할의 빈을 사용할 경우 이름 (ex: appConfig) 
FactoryMethodName : 빈을 생성할 팩토리 메소드 지정 (ex: memberRepository) 
Scope : 빈의 종류
LazyInit : 스프링 컨테이너 생성시 빈을 생성하는게 아니라, 실제 빈을 사용할 때 생성하는 방식 (생성 지연)
InitMethodName : 빈 생성과 의존관계 적용 뒤 호출되는 초기화 메서드 이름
DestroyMethodName : 빈 생명주기 종료시 제거하기 전에 호출되는 메서드 이름
Constructor arguments, properties : 의존관계 주입 관련
Role_Infrastructure : Spring 유지를 위해 자체적으로 사용하기 위해서 관리중인 Bean
Role_Application : 유저가 추가한 Bean

 

Scope, InitMethod, Destroy Method 같은 특성들은 나중에 더 자세히 다뤄보도록 하겠습니다. 실무에서

BeanDefinition 을 직접 제어할 일은 거의 없기 때문에, 너무 신경쓰지 않으셔도 됩니다. 다만 스프링의 동작

원리에 대해서는 이해하면 이해할수록 개인적으로 좋은 것 같습니다. 

 

 

 

 

포스트 요약

 

  • Application Context 는 Spring Container라고 하며, Annotation, Java, Xml 등 다양한 방법으로 설정이 된다. 
  • 설정되는 방법에 따라 Reader Class 를 구현하는데, 그 리더로 Configuration 정보를 읽어 BeanDefinition을 형성한다.
  • BeanDefinition 형성을 마치면 빈 생성 과정이 이루어지는데, 빈 생성은 생성 + 의존성 주입 두가지 단계로 나뉜다 
  • BeanFactory 는 Application Context 보다 상위 객체이며, 컨테이너를 다루는 핵심 로직을 가지고 있다. 
  • Application Context 내부에는 Bean Factory 공간이 있는데, 해당 공간에 BeanDefinition을 저장하는 Map과 실제 싱글톤으로 관리할 Bean 객체들을 저장하는 Map 공간이 있다. 
  • BeanDefinition에는 다양한 정보가 저장된다.. 

 

 

 

출처

 

 

[스프링 기본]으로 엮인 모든 포스트들은 교육 사이트 인프런의 지식공유자이신 김영한님의 [스프링 핵심 원리] 강의를 기반으로 작성되었습니다. 열심히 정리하고 스스로 공부하기 위해 만든 포스트이지만, 제대로 공부하고 싶으시면 해당 강의를 꼭 들으시는 것을 추천드립니다. 

 

 

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

 

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

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

 

 

제가 상단에 조회되는 많은 블로그를 봤지만, Bean 과 Spring Container 에 대해 기술된 블로그 중에는 이 곳이 최고입니다

 

https://leejaengjaeng.tistory.com/13

 

Spring Doc - Core -IOC Container

Spring framework Document 읽기 현재 담당하는 서비스가 Spring5를 사용하진 않지만 5의 문서를 읽으면서 추가된 내용이 아니라 Spring framework 자체의 내용에 집중해볼 예정입니다. Docs : https://docs.spring.io/s

leejaengjaeng.tistory.com

 

728x90
반응형

'Spring > Spring 기본' 카테고리의 다른 글

[Spring 기본] Component Scan을 통한 Bean 자동화 관리  (0) 2022.10.17
[Spring 기본] Spring Container의 Singleton 전략  (0) 2022.10.14
[Spring 기본] Spring의 객체 지향 IoC, DI, Bean, Container  (0) 2022.10.13
[Spring 기본] 앱 기본 설계, Config 클래스 및 주입의 시작  (0) 2022.10.13
[Spring 기본] Spring을 시작하며  (0) 2022.10.12
'Spring/Spring 기본' 카테고리의 다른 글
  • [Spring 기본] Component Scan을 통한 Bean 자동화 관리
  • [Spring 기본] Spring Container의 Singleton 전략
  • [Spring 기본] Spring의 객체 지향 IoC, DI, Bean, Container
  • [Spring 기본] 앱 기본 설계, Config 클래스 및 주입의 시작
문케이크
문케이크
    반응형
  • 문케이크
    누구나 개발할 수 있다
    문케이크
  • 전체
    오늘
    어제
    • 전체 보기 (122)
      • CS 이론 (13)
        • 운영체제 (8)
        • 네트워크 (2)
        • 알고리즘 (0)
        • Storage (3)
      • Spring (26)
        • Spring 기본 (12)
        • Spring 심화 (0)
        • JPA (11)
        • Spring Security (3)
      • 리액티브 (0)
        • RxJava (0)
      • SW 설계 (14)
        • OOP (0)
        • UML (3)
        • OOAD (0)
        • Design Pattern (11)
      • Java (8)
      • 웹 운영 (17)
        • AWS (15)
        • 운영 구축 (2)
      • Testing (3)
        • Unit (3)
      • Extra (3)
        • API 적용 (1)
      • 인프라 기술 (5)
        • Kubernetes (2)
        • Elasticsearch (3)
      • Logging (7)
        • Spring (5)
        • 인프라 (2)
      • 일상 (2)
        • 음식점 리뷰 (2)
        • Extra (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 문케이크의 블로그
  • 인기 글

  • 태그

    객체지향
    spring container
    Configuration
    di
    junit
    n+1
    composition
    OOP
    JPA
    mockito
    lazy loading
    BEAN
    Design Pattern
    GoF
    Spring
    Setter
    decorator
    elasticsearch
    디자인 패턴
    Composite
    runtime exception
    spring boot
    k8s
    김영한
    SRP
    analyzer
    Java
    OOAD
    lombok
    단위테스트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
문케이크
[Spring 기본] Container와 Bean과 조금 더 친해져보자
상단으로

티스토리툴바