徹底讀懂Spring讀源碼,我們可以從第一行讀起


徹底讀懂Spring讀源碼,我們可以從第一行讀起

文章目錄

找到第一行代碼

AnnotatedBeanDefinitionReader是什麼?

AnnotatedBeanDefinitionReader源碼解析

applyScopedProxyMode做了什麼?

1、applyScopedProxyMode

2、ScopedProxyUtils.createScopedProxy

3、ScopedProxyUtils.createScopedProxy

創建AnnotatedBeanDefinitionReader的過程中做了什麼?

1、創建environment

2、對屬性進行賦值,並註冊容器需要的bd

3、註冊容器需要的bd

總結

在前面的文章中,我們已經完成了《Spring官網閱讀》,有了上面的基礎,那麼源碼的閱讀也就不會太難了,從今天開始我們一步步走進Spring的源碼。我們整個源碼的解析將以下面這句代碼為入口:

<code>AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);/<code>


下面就跟著我來看看,Spring第一行代碼到底幹了什麼!

本系列文章對應Spring版本為5.x。

上面這行代碼就是執行了AnnotationConfigApplicationContext中的一個構造函數,其代碼如下:

public AnnotationConfigApplicationContext(Class>... annotatedClasses) {

<code>    // 1.調用了AnnotationConfigApplicationContext的空參構造方法
this();
// 2.將配置類註冊到容器中
register(annotatedClasses);
\t// 3.刷新容器
refresh();
}/<code>
<code>

找到第一行代碼

我們繼續查看AnnotationConfigApplicationContext的空參構造

其代碼如下:

<code>public AnnotationConfigApplicationContext() {
// 1.1 構造一個reader對象
this.reader = new AnnotatedBeanDefinitionReader(this);
// 1.2 構造一個scanner對象
this.scanner = new ClassPathBeanDefinitionScanner(this);
}/<code>


它主要做了兩件事

創建一個AnnotatedBeanDefinitionReader

創建一個ClassPathBeanDefinitionScanner

本文的重點就是分析第一行代碼,也就是創建AnnotatedBeanDefinitionReader的過程。在分析代碼前,我們首先應該搞懂一件事情,就是創建的這個AnnotatedBeanDefinitionReader到底是什麼呢?

AnnotatedBeanDefinitionReader是什麼?

這個類的主要作用就是註冊BeanDefinition,與之相類似的功能的類還有一個就是ClassPathBeanDefinitionScanner。它們最大的不同在於AnnotatedBeanDefinitionReader支持註冊單個的BeanDefinition,而ClassPathBeanDefinitionScanner會一次註冊所有掃描到的BeanDefinition。關於ClassPathBeanDefinitionScanner本文不專門做過多解釋,只要能看懂這篇文章ClassPathBeanDefinitionScanner自然就懂了。

如果對於BeanDefinition不瞭解的推薦先閱讀:

Spring官網閱讀(四)BeanDefinition(上)

Spring官網閱讀(五)BeanDefinition(下)

AnnotatedBeanDefinitionReader源碼解析

// 這裡只保留了這個類中的部分代碼,其餘不重要我都沒有放出來

public class AnnotatedBeanDefinitionReader {

// 上面我們已經說了,這個reader對象主要的工作就是註冊BeanDefinition,那麼將BeanDefinition註冊到哪裡去呢?所以它內部就保存了一個BeanDefinition的註冊表。對應的就是我們代碼中的AnnotationConfigApplicationContext

private final BeanDefinitionRegistry registry;

// 見名知意,Bean名稱的生成器,生成BeanName

private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

// 解析@Scope註解

private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

// 解析@Conditional註解

private ConditionEvaluator conditionEvaluator;

// 將解析指定的類成為BeanDefinition並註冊到容器中

public void registerBean(Class> annotatedClass, String name, Class extends Annotation>... qualifiers) {

doRegisterBean(annotatedClass, null, name, qualifiers);

}

// 真正的執行註冊的方法

void doRegisterBean(Class annotatedClass, @Nullable Supplier instanceSupplier, @Nullable String name,

@Nullable Class extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

// Spring在這裡寫死了,直接new了一個AnnotatedGenericBeanDefinition,也就是說通過reader對象註冊的BeanDefinition都是AnnotatedGenericBeanDefinition。

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

// 調用conditionEvaluator的shouldSkip方法

// 判斷當前的這個bd是否需要被註冊

if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {

return;

}

// 在註冊時可以提供一個instanceSupplier

abd.setInstanceSupplier(instanceSupplier);

// 解析@Scope註解,得到一個ScopeMetadata

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

// 將@Scope註解中的信息保存到bd中

abd.setScope(scopeMetadata.getScopeName());

// 調用beanNameGenerator生成beanName

// 所謂的註冊bd就是指定將bd放入到容器中的一個beanDefinitionMap中

// 其中的key就是beanName,value就是解析class後得到的bd

String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

// 這句代碼將進一步解析class上的註解信息,Spring在創建這個abd的信息時候就已經將當前的class放入其中了,所有這行代碼主要做的就是通過class對象獲取到上面的註解(包括@Lazy,@Primary,@DependsOn註解等等),然後將得到註解中對應的配置信息並放入到bd中的屬性中

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

<code>public AnnotationConfigApplicationContext() {
// 1.1 構造一個reader對象
this.reader = new AnnotatedBeanDefinitionReader(this);
// 1.2 構造一個scanner對象
this.scanner = new ClassPathBeanDefinitionScanner(this);
}/<code>

applyScopedProxyMode做了什麼?

上面的代理有一個地方沒有將清楚,就是AnnotationConfigUtils.applyScopedProxyMode到底做了什麼?

帶著這個問題,我們繼續看看這個方法的代碼

1、applyScopedProxyMode

// 這個方法名稱直譯過來就是----應用Scoped中的ProxyMode屬性

// 這個屬性有什麼用呢?

// ProxyMode屬性一共有下面幾種取值

//1.DEFAULT:默認值,默認情況下取no

//2.NO:不開啟代理

//3.INTERFACES:使用jdk動態代理

//4.TARGET_CLASS:使用cglib代理

// 假設我們有一個單例的對象A,其中有一個屬性B,B的作用域是session的,這個時候容器在啟動時創建A的過程中需要為A注入屬性B,但是屬性B的作用域為session,這種情況下注入必定會報錯的

// 但是當我們將ProxyMode屬性配置為INTERFACES/TARGET_CLASS時,它會暴露一個代理對象,ProxyMode可以配置代理對象的生成策略是使用jdk動態代理還是生成cglib動態代理,那麼當我們在創建A時,會先注入一個B的代理對象而不是直接報錯

static BeanDefinitionHolder applyScopedProxyMode(

ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

<code>\t// 根據scopedProxyMode進行判斷,如果是NO,直接返回原有的bd並添加到容器的bdMap中
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
// 是否採用cglib代理
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 調用ScopedProxyCreator的createScopedProxy,創建代理對象對應的bd
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
/<code>

2、ScopedProxyUtils.createScopedProxy

<code>public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
\t// 繼續調用ScopedProxyUtils的方法
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}/<code>


3、ScopedProxyUtils.createScopedProxy

// 根據目標對象的bd生成代理對象的bd,並且會將目標對象的bd註冊到容器中

public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,

BeanDefinitionRegistry registry, boolean proxyTargetClass) {

// 目標對象的名稱

String originalBeanName = definition.getBeanName();

// 目標對象的bd

BeanDefinition targetDefinition = definition.getBeanDefinition();

// 將來會將目標對象的bd註冊到容器中,targetBeanName作為註冊時的key

// targetBeanName = "scopedTarget."+originalBeanName

String targetBeanName = getTargetBeanName(originalBeanName);

// 創建代理對象的bd,可以看到代理對象會是一個factoryBean的介紹請參考《》,關於factoryBean的介紹請參考我的Spring官網閱讀系列第七篇,這裡不做過多介紹

RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);

<code>    // 代理對象所裝飾的bd就是目標對象的bd
// 拷貝了部分目標對象bd中的屬性到代理對象的bd中
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
\t
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.

proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// 這一步會將原始的bd註冊到容器中,其中的key="scopedTarget."+originalBeanName
registry.registerBeanDefinition(targetBeanName, targetDefinition);
\t// 返回這個用於創建代理對象的bd
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
/<code>

從上面的代碼可以看出,當我們選擇在@Scope註解中配置了proxyMode屬性時(INTERFACES/TARGET_CLASS),那麼Spring會在註冊bd時,在容器中註冊一個代理的bd,這個bd是一個ScopedProxyFactoryBean類型的bd,並且沒有特別指定它的作用域,所以它是單例的,並且這個FactoryBean返回就是對應的目標對象的代理對象。基於此,Spring就可以利用這個bd來完成在啟動階段對session/request域對象的注入。

創建AnnotatedBeanDefinitionReader的過程中做了什麼?

現在我們已經知道了這個reader對象有什麼用,那麼接下來我們就一起分析下Spring在創建這個對象的過程中還做了什麼,也就是reader對象在執行構造函數時還完成了什麼事情

1、創建environment

<code>// 第一步:調用了第一個構造函數,在這個過程中創建了environment,關於environment可以參考我的《Spring官網閱讀(十一)ApplicationContext詳細介紹(上)》 

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
// 這個environment實際上就是包含了系統環境變量以及JVM啟動參數
this(registry, getOrCreateEnvironment(registry));
}
/<code>

2、對屬性進行賦值,並註冊容器需要的bd

<code>// 第二步:進一步調用構造函數
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
\t// 為read對象中的屬性賦值
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

// 從這個方法可以看出,Spring在創建reader對象的時候就開始註冊bd了,那麼Spring註冊了哪些bd呢?註冊的bd有什麼用呢?我們接著往下看
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
/<code>

3、註冊容器需要的bd

<code>public static Set<beandefinitionholder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
\t
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {

// 1.指定容器使用的比較器,通過這個比較器能夠解析@Order註解以及Ordered接口
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}

// 2.指定容器使用的AutowireCandidateResolver
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());

}
}
Set<beandefinitionholder> beanDefs = new LinkedHashSet<>(8);
\t// 3.註冊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));
}
\t// 4.註冊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));
}
// 5.如果支持JSR-250,註冊CommonAnnotationBeanPostProcessor
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));
}
// 6.如果支持jpa,註冊PersistenceAnnotationBeanPostProcessor
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));
}
\t
// 7.註冊EventListenerMethodProcessor,用於處理@EventListener註解
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));
}
\t
// 8.註冊DefaultEventListenerFactory,用於將@EventListener所標註的方法轉換成EventListener對象
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;
}
/<beandefinitionholder>/<beandefinitionholder>/<code>

上面這段代碼,主要做了8件事,接下來我們就詳細看看

指定容器使用的比較器,通過這個比較器能夠解析@Order註解以及Ordered接口

指定容器中使用的比較器為AnnotationAwareOrderComparator,這個比較器繼承了OrderComparator。

OrderComparator自身提供了對Ordered接口的處理功能,而AnnotationAwareOrderComparator進一步做了擴展,除了會處理Ordered接口外還會處理@Order註解,但是接口的優先級高於註解。

指定容器使用的AutowireCandidateResolver

參考我之前的問題:Spring中的AutowireCandidateResolver

這個類主要是在依賴注入期間起作用

判斷一個bean的類型是否符合依賴的條件

處理@Vlaue註解

處理@Qualifier註解

處理@Lazy註解為延遲注入的依賴生成代理

註冊ConfigurationClassPostProcessor

這個類是Spring啟動過程中非常重要的一個後置處理器,它完成了對配置類的解析,並根據配置類上的配置信息去進行掃描並將掃描得到的bd註冊到容器中,之後又會去解析註冊到容器中的bd(因為在前一次掃描中可能會註冊新的配置類),重複上面的操作確保所有的配置類都被解析處理完成。

這個類的源碼之後單獨用一篇文章分析,本文就不過多介紹了。

只要記住一點,Spring在構建Reader對象時就已經將這個後置處理器添加到容器中了,這個後置處理器屬於**“開天闢地”**的那一類Bean

註冊AutowiredAnnotationBeanPostProcessor

這個後置處理器主要工作於依賴注入階段,專門用於處理@Autowired註解

如果支持JSR-250,註冊CommonAnnotationBeanPostProcessor

這個後置處理器也是工作於依賴注入階段,專門用於處理@Inject註解

如果支持jpa,註冊PersistenceAnnotationBeanPostProcessor

提供了JPA的支持,不是重點,瞭解即可

註冊EventListenerMethodProcessor,用於處理@EventListener註解

在Spring完成Bean的創建後,會調用這個處理器的afterSingletonsInstantiated,在這個方法中會完成@EventListener註解的解析,將所有的@EventListener註解標註的方法通過後面註冊的DefaultEventListenerFactory轉換成為ApplicationListener並註冊到容器中

註冊DefaultEventListenerFactory

將@EventListener標註的方法轉換成ApplicationListener

至此,整個AnnotatedBeanDefinitionReader創建完成。

總結

本文作為Spring源碼閱讀系列的第一篇,主要介紹了整個AnnotatedBeanDefinitionReader的創建過程。我們從AnnotatedBeanDefinitionReader是什麼開始,詳細介紹了Spring的第一行代碼到底幹了什麼。

可以看到,Spring在創建AnnotatedBeanDefinitionReader的過程中,還往容器中添加了開天闢地用的幾個後置處理器,關於這幾個後置處理器我將會在後面的文章中做詳細的介紹。

源碼的學習過程是枯燥的,這一系列的文章的目的一方面是總結自己在閱讀Spring的源碼過程中一些心得,朝著精通Spring的方向發展,一方面也希望能幫助到那些跟我一樣正在學習Spring的同學可以減少一些源碼閱讀過程中的困擾。

給自己加油,也給在學習過程中的你們加油~!


分享到:


相關文章: