[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 클래스 및 주입의 시작
문케이크
문케이크
    반응형
  • 문케이크
    누구나 개발할 수 있다
    문케이크
  • 전체
    오늘
    어제
    • 전체 보기 (124)
      • CS 이론 (14)
        • 운영체제 (8)
        • 네트워크 (2)
        • 알고리즘 (0)
        • Storage (3)
        • JVM (1)
      • 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)
  • 블로그 메뉴

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

  • 공지사항

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

  • 태그

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

  • 최근 글

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

티스토리툴바