스프링

스프링 기초 - 스프링 컨테이너

ho코딩 2024. 2. 14. 01:00

이전 시간에 ApplicationContext를 통해 스프링 컨테이너를 만들어 보았습니다. 

 

다시 정리해 보자면 ApplicationContext는 인터페이스이고 

XML 기반의 설정 클래스와 , 자바 기반의 설정 클래스를 만들 수 있다고 했습니다. 

 

그 중 JAVA기반의 AnnotationCofigApplicationContext를 사용하였고 이는 ApplicationContext 인터페이스의 구현체입니다.

 

 

 

스프링 컨테이너는 `new AnnotationConfigApplicationContext(AppConfig.class)`를 통해서 생성됩니다. 

스프링 컨테이너를 생성 할 때는 구성 정보를 지정해줘야하는데 위 코드에서 보면 알 수 있듯 AppConfig.class로 설정

 

그러면 스프링 컨테이너는 파라미터로 넘어온 AppConfig 클래스의 정보를 사용해서 스프링 빈을 등록합니다. 

 

@Bean 어노테이션이 달려있는 메서드 이름을 빈 이름으로 사용하고 

반환값으로 사용된 것을 빈 객체로 사용합니다. 

 

한편, `@Bean(name="memberService2")` 이처럼 어노테션 옆에 (name= )을 사용하면 이름 지정도 가능합니다. 

+ 빈 이름은 항상 다름 이름을 부여해야합니다 -> 같은 이름 부여시 다른 빈이 무시or오류 발생

 

 

 

 

 

이렇게 컨테이너에 등록된 빈 들은 

설정 정보를 참고하여 의존관계를 주입(DI)합니다. 

위 두 사진은 각기 다른 단계처럼 보이지만 보통 생성자 호출하면서 의존관계도 한 번에 처리됩니다. 

 

 

 

 

 

빈이 정상적으로 등록이 잘 됐는지 확인하는 테스트 코드는 

 

위 이미지와 같습니다. 

 

ac.getBeanDefinitionName()을 사용하면 스프링에 등록된 모든 빈 이름을 조회합니다. 

ac.getBean(빈이름): 빈 이름으로 빈 객체(인스턴스)를 조회합니다. 

 

 

 

조회하는 방법은 빈 이름/ 타입 / 구체 타입으로 조회가 있습니다.

 

 

 

 

 

 

스프링 빈 조회- 상속 관계

 

 

부모 타입으로 조회하면, 자식 타입도 함께 조회됩니다. 

그래서 모든 자바 객체의 최고 부모인 Object타입으로 조회하면, 모든 스프링 빈을 조회하게 됩니다. 

 

 

 

 

 

 

 

 

BeanFactory / ApplicationContext

 

위에서 계속 사용했던 ApplicationContext는 무엇인가에 대해 더 자세히 알아보겠습니다.

 

BeanFactory의 계층 구조 입니다. 

 

BeanFactory는 스프링 컨테이너의 최상위 인터페이스 입니다. 

스프링 빈을 관리하고 조회하는 역할을 담당하며, 위에서 사용한 getBean()을 제공하는 주체입니다. 

이외에도 다양한 기능의 대부분은 BeanFactory가 제공하는 기능입니다. 

 

ApplicationContext 

-앞에서도 어느정도 설명했지만, 보강하자면 계층구조를 보면 알 수 있듯, BeanFactory의 기능을 모두 상속받습니다. 

-하지만 BeanFactory와의 차이점을 말하자면 몇가지 부가기능이 더 존재합니다

ApplicationContext

 

ApplicationContext는 BeanFactory외에도 다양한 인터페이스들을 상속받고 있습니다. 

각각은 

1. 메시지소스를 활용한 국제화 기능 = 한국에서 들어오면 한국어 / 영어권에서 들어오면 영어 출력

2. 환경변수 = 로컬, 개발 , 운영등을 구분해서 처리 

3. 애플리케이션 이벤트 = 이벤트를 발행하고 구독하는 모델을 편리하게 지원 

4. 편리한 리소스 조회 = 파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회

의 기능을 부가적으로 가지고 있습니다. 

 

때문에 사실상 Beanfactory를 직접 사용할 일은 거의 없고 부가기능이 포함된 ApplicationContext를 사용합니다. 

 

 

Xml 설정 형식

 

 

JAVA코드를 사용한 설정 파일 (AppConfig.class)도 있지만 XML 형식의 설정 형식도 지원합니다. 

 

 

ApplicationContext를 구현한 여러 클래스 들이 있는데 

그 중 AnnotationConfigApplicationContext = Java 설정코드를 사용한 것이고 

GenericXml ApplicationContext은 Xml을 설정코드로 사용한 것 입니다. 

 

GenericXmlApplicationContext를 사용한 Test 코드
xml 설정 코드

 

JAVA 코드와 비교했을 때 거의 비슷한 설정 정보입니다. 

 

다만 최근에는 XML 기반의 설정 정보를 잘 사용하지 않습니다. 

 

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

 

 

 

스프링이 이런 다양한 설정 형식을 지원하는 방법은 무엇일까? 

 

그 중심에는 BeanDefinition이라는 추상화가 있습니다. 

-> '역할'과 '구현'을 개념적으로 나눈다 . 

-> JAVA 코드를 읽어서 BeanDefinition을 만들고. xml을 읽어서 BeanDefinition을 만든다. 

 

사실 저도 잘 와닿지 않는데, 

 

BeanDefinition을 빈 설정 메타정보라고 합니다. 

@Bean, <bean>당 각각 하나씩 메타 정보가 생성되고 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성합니다. 

 

더 자세히 살펴보면 

 

맨 왼쪽을 보면 AnnotationConfigApplicationContext는 AnnotatedBeanDefinitionReader를 사용하여 

자바코드로 된 AppConfig.class 파일을 읽고 BeanDefinition을 생성합니다. 

 

 

대체 BeanDefinition은 무엇인가? 

BeanDefinition은 스프링 프레임워크에서 빈을 정의하고 구성하는 메타데이터를 나타내는 '인터페이스'입니다. 

 

메타데이터에는 빈의 클래스 / 범위(scope) / 라이프사이클 콜백 메서드/ 의존성 등을 포함합니다. 

정리해서 말하자면 ) 스프링 컨테이너가 빈을 어떻게 생성하고 관리해야 하는지에 대한 정보를 담고 있는 객체입니다. 

 

BeanDefinition 정보를 더 자세히 들여다보면

1. BeanClassName: 생성할 빈의 클래스 명 (자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음) 

2. factoryBeanName: 팩토리 역할의 빈을 사용할 경우 이름 (ex) 앞서 사용한 AppConfig 

3. factoryMethodName: 빈을 생성할 팩토리 메서드 지정 , 예)memberService

4. Scope : 싱글톤 (기본값) -> 다음 장에 더 자세히 설명할 예정 

5.initMethodName: 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명 

6. DestroyMethodName: 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명 

7. Constructor arguments, Properties: 의존관계 주입에서 사용 

8.lazyInit: 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때 까지 최대한 생성을 지연처리하는지 여부 

 

-> 이러한 내용을 BeanDefinition이 가지고 있으며 참고 정도하면 하면 된다. 

-> 가볍게 BeanDefinition을 이해하고,

스프링이 다양한 형태의 설정 정보를 BeanDefinition으로 추상화해서 사용하는 것 정도만 이해하자 !