1.BeanFactory和ApplicationContext
我們先檢視ApplicationContext的類圖吧(IDEA快捷鍵Ctrl+Alt+U)
我們會發現BeanFactory是Application的父類,那麼他們兩者有什麼差別呢
我們先來了解他們的作用
BeanFactory:
是Spring裡面最低層的接口,提供了最簡單的容器的功能,隻提供了執行個體化對象和拿對象的功能;
ApplicationContext:
應用上下文,繼承BeanFactory所有的功能,它是Spring的一各更進階的容器,提供了更多的有用的功能;
- 國際化(MessageSource)
- 通路資源,如URL和檔案(ResourceLoader)
- 載入多個(有繼承關系)上下文 ,使得每一個上下文都專注于一個特定的層次,比如應用的web層
- 消息發送、響應機制(ApplicationEventPublisher)
- AOP(攔截器)
兩者裝載bean的差別
BeanFactory:
BeanFactory在啟動的時候不會去執行個體化Bean,中有從容器中拿Bean的時候才會去執行個體化;
ApplicationContext:
ApplicationContext在啟動的時候就把所有的Bean全部執行個體化了。
延遲執行個體化的優點:(BeanFactory)
應用啟動的時候占用資源很少;對資源要求較高的應用,比較有優勢;
不延遲執行個體化的優點: (ApplicationContext)
- 所有的Bean在啟動的時候都加載,系統運作的速度快;
- 在啟動的時候所有的Bean都加載了,我們就能在系統啟動的時候,盡早的發現系統中的配置問題
- 建議web應用,在啟動的時候就把所有的Bean都加載了。
2.AnnotationConfig啟動方式解析
建立MyConfig.java
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
}
Application.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContextExtensionsKt;
public class Application {
public static void main(String[] args) {
// ApplicationContext
new AnnotationConfigApplicationContext(MyConfig.class);
}
}
源碼檢視AnnotationConfigApplicationContext
進入的此詞方法,說明我們啟動需要先經過這三個方法,我們先來看this(),點選檢視
跳轉到無參構造中來,但是,我們看方法必須要先看類,看他是否有繼承(這點很重要,因為作為子類,執行之前都得先執行父類),是以跳轉過來,我們會發現AnnotationConfigApplicationContext繼承了GenericApplicationContext。
這個很重要,後面我們會用到
好了,我們再次回到this.reader,this.scanner。他們兩個很好了解,一個是讀取(注解),一個是掃描(掃包)
this()看完了,
接下來看this.register(annotatedClasses)
好了,終于到頭了
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 我們之前學習過RootBeanDefinition,它是用于傳統方式往IOC容器注入bean
// 一樣的 AnnotatedGenericBeanDefinition 屬于注解方式注入bean
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// 判斷是否使用condition 條件注冊
if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
// 用于建立bean執行個體的回調
abd.setInstanceSupplier(instanceSupplier);
// 解析bean作用域(單例或者原型),如果有@Scope注解,則解析@Scope,沒有則預設為singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 作用域寫回BeanDefinition資料結構, abd中缺損的情況下為空,将預設值singleton重新指派到abd
abd.setScope(scopeMetadata.getScopeName());
// 生成bean配置類beanName
String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
// 通用注解解析到abd結構中,主要是處理Lazy, primary DependsOn, Role ,Description這五個注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
int var10;
int var11;
// @Qualifier特殊限定符處理,@Qualifier 除了bean類級别的限定符之外,要考慮的限定符特定限定符注釋
if (qualifiers != null) {
Class[] var9 = qualifiers;
var10 = qualifiers.length;
for(var11 = 0; var11 < var10; ++var11) {
Class<? extends Annotation> qualifier = var9[var11];
if (Primary.class == qualifier) {
// 如果配置@Primary注解,則設定目前Bean為自動裝配autowire時首選bean
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
// 設定目前bean為延遲加載
abd.setLazyInit(true);
} else {
// //其他注解,則添加到abd結構中
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
BeanDefinitionCustomizer[] var13 = definitionCustomizers;
var10 = definitionCustomizers.length;
// 自定義bean注冊,通常用在applicationContext建立後,手動向容器中一lambda表達式的方式注冊bean
for(var11 = 0; var11 < var10; ++var11) {
BeanDefinitionCustomizer customizer = var13[var11];
// //自定義bean添加到BeanDefinition
customizer.customize(abd);
}
// 根據beanName和bean定義資訊封裝一個beanHolder,beanHolder其實就是一個 beanname和BeanDefinition的映射
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 根據注解Bean定義類中配置的作用域@Scope注解的值,為Bean定義應用相應的代理模式
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 按名稱将bean定義資訊注冊到容器中,實際上DefaultListableBeanFactory内部維護一個Map<String, BeanDefinition>類型變量beanDefinitionMap beanDefinitionMap用來儲存beanName,BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
register方法重點完成了bean配置類本身的基本資訊注冊
接下來看this.refresh()
----後期補充-----