본문 바로가기

Spring/Spring

(SPRING) Spring ApplicationContext의 내부 (2)

https://jwdeveloper.tistory.com/189

 

(SPRING) Spring ApplicationContext의 내부 (1)

요즘 스프링의 ApplicationContext의 빈 생성 원리에 대해서 2주 동안 지속적으로 살펴보았다. 어려워서 2주간의 시간이 걸린 것이 아니라 감탄 + 복잡하게 얽혀있는 인터페이스 추상클래스 클래스 와의 관계 때..

jwdeveloper.tistory.com

이때까지 살펴보았던 과정은 인스턴스를 생성하거나 초기화하는 과정이었다.

이제 실질적으로 Bean을 등록하는 과정을 살펴보자

Bean을 등록하는 메서드는 register로부터 시작된다.


사실 실질적으로 등록되는 메서드는 아래 doRegisterBean 메서드이다.

doRegisterBean(Class <T>, @Nullable String name,
@Nullable Class <? extends Annotation>[] qualifiers, @Nullable Supplier <T> supplier,
@Nullable BeanDefinitionCustomizer [] customizers)

/**
 * Register a bean from the given bean class, deriving its metadata from class-declared annotations.
 */

명세에 위와 같이 주어진 Bean 클래스로부터 Bean을 등록하고 그 과정에서 클래스에 선언된 어노테이션을 기반으로 메타데이터를 가져온다고 적혀있다.

 

doRegisterBean은 우리가 이전에 정보를 등록한 AnnotatedBeanDefinitionReader 클래스 내부에 있다.


AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

먼저 AnnotatedGenericBeanDefinition의 인스턴스를 생성한다. (아규먼트는 beanClass)

AnnotatedGenericBeanDefinition가 핵심이므로 해당 클래스에 대한 상속 구조를 명확하게 해 두는 것이 좋을 것 같다.

 

GenericBeanDefinition

AbstractBeanDefinition

의 인스턴스 또한 함께 생성한다.

 

setBeanClass(beanClass);

AbstractBeanDefinition에 해당 클래스에 대한 정보를 저장한다.


메타데이터 가져오기

this.metadata = AnnotationMetadata.introspect(beanClass);

https://dahyeee.tistory.com/entry/JAVA-interface-default-static%EB%A9%94%EC%86%8C%EB%93%9C

 

[JAVA] interface (default, static메소드)

Java version 8에서 interface에 default 메소드와 static 메소드가 사용가능하게 되었다고 합니다. 소스를 통해 설명드리겠습니다. 1. Calculator.java 2, 3번째 줄 : 일반 메소드 선언 (추상메소드의 역할 abstr..

dahyeee.tistory.com

AnnotationMetadata는 인터페이스이다. 해당 클래스 내부에 구현이 완성되어있는 introspect 메서드가 존재한다. 해당 메서드는 하위 클래스인 StandardAnnotationMetadata에게 메시지를 전달한다.

저장하는 정보는 SearchStrategy = INHERITED_ANNOTATIONS  ,  nestedAnnotationsAsMap = True클래스에 대한 정보이다. (MergedAnnotations에 저장)


Scope 지정하기

AnnotationScopeMetadataResolver에 있는 Scope에 대한 메타 데이터를 가져와서 Scope을 지정한다.

private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

ScopeMetadataResolver는 인터페이스이고 AnnotationScopeMetadataResolver는 해당 인터페이스의 구현체이다.

따라서 아래와 같이 resolveScopeMetadata 메시지를 AnnotationScopeMetadataResolver에게 전달한다. 결과만 받으면 AnnotationScopeMetadataResolver가 어떻게 처리하든 상관하지 않는다.

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

또한 결과를 ScopeMetadata라는 DTO 객체에 담아서 리턴한다는 점이 흥미롭다.

 

 

 

해당 DTO 객체는 디폴트 값으로 싱글톤이 설정되어있다.

실행 결과


빈 이름 설정하기

 

private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

위와 같다.

 

하지만 여기에선 싱글톤 형식으로 인스턴스를 여러 번 생성하지 못하도록 하였다.

private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();

해당 구조를 다시 상기시켜면서...

 

AnnotatedGenericBeanDefinition 은 BeanDefinition의 구체 클래스이므로

다형성을 활용하여 모든 타입은 BeanDefinition으로 받는다.

 

 

해당 과정을 통해 BeanName을 설정한다.

return buildDefaultBeanName(definition, registry);

내부의 과정은 bean의 이름을 가져와서 풀 패키지 경로를 클래스 명으로 줄이는 과정이다.

 

 

 


refresh()

https://github.com/mike6321/Spring/blob/master/Spring/ApplicationContext%20Core(3)%20-%20refresh().md

 

mike6321/Spring

Contribute to mike6321/Spring development by creating an account on GitHub.

github.com