spring 소스 코드 시리즈 (3) AnnotationConfigapplicationContext 초기 화 분석
17360 단어 스프링 소스 코드
AnnotationConfigApplicationContext spring , AnnotationConfigApplicationContext , bean 。
초기 화 과정 에서 관련 된 중요 한 클래스 와 속성:
클래스 또는 속성
묘사 하 다.
AnnotationConfigApplicationContext
spring 상하 문 환경
GenericApplicationContext
AnnotationConfigApplicationContext 부 류 는 이곳 에서 화학 공장 을 시작 할 것 이다.
DefaultListableBeanFactory
spring bean 공장, bean 창설 에 사용
beanDefinitionMap
DefaultListable BeanFactory 의 속성 은 BeanDefinition 을 저장 하 는 데 사 용 됩 니 다. bean name 을 key 로 하고 BeanDefinition 을 value 로 합 니 다.
beanDefinitionNames
list 집합, 모든 bean 저장 name
BeanDefinition
jdk 의 class 클래스 와 비슷 합 니 다. bean 의 클래스 를 묘사 하 는 데 사 용 됩 니 다. beanClassName, scope, lazyIni, dependsOn 등 속성 이 있 습 니 다.
AnnotatedBeanDefinitionReader
주 해 를 추가 한 bean 을 읽 기 위해 읽 은 데 이 터 를 BeanDefinition 에 저장 합 니 다.
BeanDefinitionRegistry
등록 기 는 BeanDefinition 등록 을 Default Listable BeanFactory 에 저장 하 는 데 사 용 됩 니 다. 또한 reader 에서 초기 화 할 때 AnnotationConfigApplication Context 대상 자체 가 들 어 오기 때문에 AnnotationConfigApplication Context 환경 과 같 습 니 다.
2. 소스 코드 분석
1. AnnotationConfigApplication Context 구조 방법
AnnotationConfigApplication Context 는 네 가지 구조 방법 을 제공 합 니 다. 구체 적 인 코드 는 다음 과 같 습 니 다.
/**
* AnnotationConfigApplicationContext, spring , ,
*
*/
public AnnotationConfigApplicationContext() {
/**
* AnnotatedBeanDefinition , bean,
* AnnotatedBeanDefinition
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
/**
* , , bean AnnotatedBeanDefinition
*/
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigApplicationContext(Class>... componentClasses) {
/**
* this , super()
*/
this();
/**
* bean, , bean
*
*/
register(componentClasses);
refresh();
}
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
주의해 야 할 것 은 무 참 구조 방법 을 사용 할 경우 register () 또는 scan () 방법 을 수 동 으로 호출 해 야 하 며, 마지막 으로 refresh () 방법 이 필요 하 다 는 점 이다. 본 고 는 Public AnnotationConfigApplication Context (Class >... componentClasses) 를 예 로 들 어 분석 하고 자 한다.이 구조 방법 은 세 부분 으로 나 눌 수 있다.
1)this
2)register()
3)refresh()
2. this()
하위 구조 방법 을 집행 할 때 먼저 부류 구조 방법, 즉 this () 방법의 집행 이 먼저 부류 의 구조 방법 을 집행 한다 면 부류 구조 방법 부터 살 펴 보 자.
AnnotationConfigApplicationContext GenericApplicationContext 에서 계승
public GenericApplicationContext() {
/**
* , bean
* @reviewer wangcongming
*/
this.beanFactory = new DefaultListableBeanFactory();
}
GenericApplication Context 에서 공장 클래스 Default Listable Bean Factory 를 초기 화 했 습 니 다.다음은 DefaultListableBeanFactory 의 중요 한 속성 을 간단하게 보 여 줍 니 다. 그 중에서 beanDefinitionMap 은 BeanDefinition (bean 의 클래스 설명) 을 저장 하 는 데 사 용 됩 니 다. beanDefinitionNames 는 모든 bean name 을 저장 하 는 데 사 용 됩 니 다.
/**
*
* @reviewer wangcongming
*/
@Nullable
private Comparator
부모 클래스 구조 가 완료 되면 하위 클래스 (AnnotationConfigApplication Context) 의 초기 화 를 볼 수 있 습 니 다.
/**
* AnnotatedBeanDefinition , bean,
* AnnotatedBeanDefinition
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
/**
* , , bean AnnotatedBeanDefinition
*/
this.scanner = new ClassPathBeanDefinitionScanner(this);
이 를 통 해 알 수 있 듯 이 AnnotationConfigApplication Context 의 무 참 구조 에서 두 가지 일 만 했 고 하나의 리더 (Annotated Bean DefinitionReader) 와 하나의 스캐너 (ClassPathBean DefinitionScanner) 를 초기 화 했다.
리더 AnnotatedBeanDefinitionReader
말 그대로 판독 기 는 bean 을 읽 는 데 사 용 됩 니 다. bean 을 읽 어서 BeanDefinition 대상 을 만 드 는 역할 을 합 니 다. 마지막 으로 BeanDefinition 대상 을 Default Listable BeanFactory 의 beanDefinitionMap 에 저장 합 니 다.
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
AnnotationConfigApplication Context 에서 리더 기 를 만 들 때 this 즉 대상 자 체 를 들 여 옵 니 다. Annotated Bean DefinitionReader 에 서 는 Bean DefinitionRegistry 를 사용 하여 받 습 니 다. 그러면 Bean DefinitionRegistry 는 AnnotationConfigApplication Context 와 같 고 모두 spring 용기 의 컨 텍스트 환경 이 라 고 볼 수 있 습 니 다.그럼 빈 데 피 니 션 레 지 스 트 리 는 뭐 하 는 거 예요?실제로 Bean Definition Registry 는 bean 을 등록 하 는 데 사용 되 는 등록 기 입 니 다.Annotated BeanDefinitionReader 에서 읽 은 BeanDefinition 은 BeanDefinitionRegistry 를 통 해 Default Listable BeanFactory 에 등 록 된 beanDefinitionMap 입 니 다.
이 구조 방법 은 최종 적 으로 AnnotationConfigUtils. registerAnnotationConfigProcessors (this. registry) 에 의뢰 합 니 다.뭔 가 를 했 어 요.
/**
*
*/
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
public static Set registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// registry DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
//
if (beanFactory != null) {
//set
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
// set
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set beanDefs = new LinkedHashSet<>(8);
// spring bean, ,
//ConfigurationClassPostProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//AutowiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// JSR-250
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// jpa
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
스캐너 ClassPathBeanDefinitionScanner
스캐너 는 클래스 패 키 지 를 스 캔 하 는 데 사 용 됩 니 다. 주로 설정 클래스 의 @ Componentscan 주석 설정 의 속성 을 스 캔 하 는 데 사 용 됩 니 다.
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
scanner 에서 도 Bean Definition Registry 를 초기 화 한 것 을 알 수 있 습 니 다. 이 는 scanner 스 캔 류 를 스 캔 할 때 생 성 된 Bean Definition 대상 을 Default Listable Bean Factory 공장 의 bean Definition Map 에 등록 해 야 하기 때 문 입 니 다.
3. register()
public void register(Class>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
register () 방법 은 하나 이상 의 bean 을 등록 할 수 있 습 니 다. 이 bean 은 하나의 설정 류 일 수도 있 고 일반적인 bean 일 수도 있 습 니 다. 이 방법 자체 가 아무것도 하지 않 았 음 을 알 수 있 습 니 다. 진정한 등록 기능 을 reader 에 의뢰 하여 처리 합 니 다.이것 은 바로 위 에서 말 한 reader 는 bean 을 읽 고 읽 은 데 이 터 를 BeanDefinition 에 저장 하 는 데 사 용 됩 니 다.
public void register(Class>... componentClasses) {
// bean
for (Class> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class> beanClass) {
doRegisterBean(beanClass, null, null, null);
}
void doRegisterBean(Class beanClass, @Nullable Supplier instanceSupplier, @Nullable String name,
@Nullable Class extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
/**
*
* bean bean class BeanDefinition
* @reviewer wangcongming
*/
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//abd.getMetadata() 、 、 Class
// conditionEvaluator#shouldSkip , Class 。
// : @Configuration 。 Condition , ~
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
/**
* bean
* @reviewer wangcongming
*/
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
/**
*
* bean name
* @reviewer wangcongming
*/
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
/**
*
* @reviewer wangcongming
*/
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
/**
* qualifiers ,
*/
if (qualifiers != null) {
for (Class extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
/**
* ,
* @reviewer wangcongming
*/
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
/**
* BeanDefinitionHolder BeanDefinition beanName ,
* @reviewer wangcongming
*/
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
doRegisterBean () 방법 은 bean 을 읽 고 BeanDefinition 을 map 에 저장 하 는 것 입 니 다.
코드 를 보 니 BeanDefinitionRegistry 를 사용 하여 BeanDefinition 을 factory 의 beanDefinitionMap 에 등록 하 였 습 니 다.
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
/**
*
* @reviewer wangcongming
*/
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
/**
* map beanName BeanDefinition
* bean
* @reviewer wangcongming
*/
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
/**
* beanDefinition map, beanName beanDefinitionNames
* @reviewer wangcongming
*/
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
// BeanDefinition
resetBeanDefinition(beanName);
}
}
4) refresh()
앞부분 에 초기 화 된 환경 (사용 할 대상 초기 화) 이 준비 되 어 있 습 니 다. refresh () 방법 은 bean 및 공장 백업 프로세서 (BeanFactory PostProcessor) 를 읽 기 시작 하 는 것 입 니 다. spring 의 많은 기능 은 BeanFactory PostProcessor 를 통 해 이 루어 집 니 다. 설정 류 의 스 캔 을 포함 합 니 다.
계속