前言
上篇博客spring 5.0.x源碼學(xué)習(xí)系列三: AnnotationConfigApplicationContext類的無參構(gòu)造方法的作用介紹了AnnotationConfigApplicationContext類無參構(gòu)造方法的作用, 再次回顧下主要有如下幾個(gè)作用:
- 初始化spring bean工廠
DefaultListableBeanFactory
- 通過
AnnotatedBeanDefinitionReader
將spring6個(gè)內(nèi)置bean以RootBeanDefinition到bean
的類型注冊到工廠, 其中要記住最重要的ConfigurationClassPostProcessor
- 初始化
ClassPathBeanDefinitionScan
(這個(gè)沒啥用, 真正的掃描邏輯并不是用到它) - AnnotationConfigApplicationContext的幾個(gè)身份:
BeanDefinitionRegistry
和GenericApplicationContext
接下來進(jìn)入正文: AnnotationConfigApplicationContext類register方法作用
一艾船、項(xiàng)目demo
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
一道媚、AnnotationConfigApplicationContext類register方法api
- 從上之下的源碼就是它的執(zhí)行過程, 附帶注釋
// AnnotationConfigApplicationContext.java
/**
* 顧名思義踊兜,傳入的是被注解的類精刷,并且在里面做了是否存在注解的校驗(yàn)(可以傳多個(gè)類)
* 根據(jù)代碼可知: 又是通過AnnotatedBeanDefinitionReader來注冊的
*/
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
// AnnotationConfigApplicationContext.java
/**
* 因?yàn)樯鲜鯽pi提供的是一個(gè)可變參數(shù), 所以此處要遍歷注冊它
*/
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
// AnnotationConfigApplicationContext.java
/**
* 將代碼邏輯委托給另外方法
*/
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
// AnnotationConfigApplicationContext.java
/**
* 由調(diào)用鏈可知鸵贬,調(diào)用此方法時(shí), 只有第一個(gè)參數(shù)有值,其他的都為null
* @param annotatedClass
* @param instanceSupplier
* @param name
* @param qualifiers
* @param definitionCustomizers
* @param <T>
*/
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 記住這個(gè)創(chuàng)建beanDefinition的api, 很常用诫尽。
// 在利用spring擴(kuò)展點(diǎn)動(dòng)態(tài)添加一些beanDefinition至bean工廠時(shí)很有用
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// set進(jìn)去的為null, 因?yàn)閭鬟M(jìn)來的為null
abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 這塊用的是當(dāng)前類默認(rèn)的beanNameGenerator => AnnotationBeanNameGenerator
// private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
// 并不會(huì)使用到我們自定義的beanNameGenerator, 為什么区岗?
// 因?yàn)槲覀儔焊瓦€沒解析到@ComponentScan注解(這里需要有一點(diǎn)自定義beanNameGenerator的知識(shí)點(diǎn))
// 大致可以參考我Github中的這個(gè)類:
// https://github.com/AvengerEug/spring/blob/develop/ioc/src/main/java/com/eugene/sumarry/ioc/annotationtype/MyBeanNameGenerator.java
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 這里開始處理一些通用的注解: 比如@Lazy、@Primary眠菇、@DependsOn辫呻、@Role、@Description
// 獲取到這些注解中的值, 并填充至傳入的AnnotatedGenericBeanDefinition
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 這塊如果按照spring的流程來基本上用不上, 因?yàn)閭魅氲氖莕ull
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));
}
}
}
// 傳入的也為null, 按照正常流程來, 先忽略它
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 不知道是為了啥, 要new這么一個(gè)對象, 可能只是為了方便傳值吧 - -琼锋!
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 這塊暫時(shí)不知道放闺。。缕坎。
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注冊beanDefinition, 傳入的是registry, 有了上篇博客的基礎(chǔ)怖侦,
// 易知該registry就是AnnotationConfigApplicationContext
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
// BeanDefinitionReaderUtils.java
/**
* 注冊beanDefinition
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 它前面封裝了一個(gè)definitionHolder, 現(xiàn)在又拆解它......
// 該register是一個(gè)AnnotationConfigApplicationContext
// 但此時(shí)是調(diào)用父類GenericApplicationContext的registerBeanDefinition方法
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
// DefaultListableBeanFactory.java
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");
// 這里會(huì)校驗(yàn)當(dāng)前的beanDefinition, 具體校驗(yàn)啥沒具體看,
// 但beanDefinition instanceof AbstractBeanDefinition條件是成立的
// 因?yàn)樗?AnnotatedGenericBeanDefinition)繼承了AbstractBeanDefinition
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// beanDefinitionMap: 這個(gè)屬性是bean工廠存放定義的beanDefinition
// 因?yàn)橐詁eanDefinition, 所以先校驗(yàn)它是否存在, 正常流程中
// 這里基本為null
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isWarnEnabled()) {
logger.warn("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.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判斷bean是否在創(chuàng)建, 正常的register流程中, 返回的基本為false
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// 將beanD注冊到bean工廠中,
// 1. 添加到beanDefinitionMap
// 2. 添加到beanDefinitionNames
// 3. 從manualSingletonNames中移除, 這里不清楚manualSingletonNames
// 屬性是干啥的, 不過根據(jù)名字來猜測: 存放手動(dòng)創(chuàng)建的單例bean的名字谜叹?
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
二匾寝、運(yùn)行結(jié)果
在這里插入圖片描述
在這里插入圖片描述
三、小結(jié)
- Q1: 上面的代碼執(zhí)行完后(register方法執(zhí)行完畢)荷腊,往bean工廠中注冊了幾個(gè)beanDefinition, bean工廠中一共有幾個(gè)beanDefinition艳悔?
- A1: 注冊了
2
個(gè)beanDefinition, 此時(shí)bean工廠中一共有6 + 2 = 8
個(gè)beanDefinition。
- Q2: 現(xiàn)在bean工廠中存在的beanDefinition的類型總共有幾種女仰?分別是猜年?
- A2: 兩種。 分別是
RootBeanDefinition
和AnnotatedGenericBeanDefinition
疾忍。
- Q3: 現(xiàn)在有bean被創(chuàng)建出來嗎乔外?
- A3: 沒有, register方法只是注冊beanDefinition。 一般是注冊一個(gè)配置類(eg: 包含@ComponentScan注解的類)方便spring的后續(xù)操作(eg: 掃描包解析注解等等)一罩。
- Q4: spring認(rèn)為描述bean的通用注解有哪些杨幼?
- A4: @Lazy、@Primary聂渊、@DependsOn差购、@Role、@Description
- spring源碼學(xué)習(xí)對應(yīng)GitHub 地址https://github.com/AvengerEug/spring/tree/develop/resourcecode-study
- I am a slow walker, but I never walk backwards.