1. 程式人生 > 程式設計 >Spring原始碼解析系列一:配置類的初始化過程

Spring原始碼解析系列一:配置類的初始化過程

從今天開始,準備寫關於Spring原始碼的部落格,那麼廢話不多說,咱們開始搞!

1.環境準備

1).看圖:

PersonService類:

@Component
public class PersonService {
	public void run(){
		System.out.println("run方法執行了");
	}
}
複製程式碼

SpringConfiguration類:

@ComponentScan("my.blog")
public class SpringConfiguration {

}
複製程式碼

Test01類:

public class Test01 {
	public
static void main(String[] args)
{ //這個構造方法會把Spring所有的環境都準備好 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); PersonService person = ac.getBean(PersonService.class); person.run(); } } 複製程式碼

2.介紹:註解配置應用上下文

AnnotationConfigApplicationContext

顧名思義:註解配置應用上下文,我在演示當中使用的是註解的方式

所以需要 new AnnotationConfigApplicationContext 這個物件.

如果採用的是xml的配置方式 則需要 new ClassPathXmlApplicationContext,這個應該我不用多說,我想你應該懂的!

那麼這個例項化物件的過程,Spring到底中幹了哪些見不得人的事呢? 接下來跟著我一起去揭開他的神祕面紗!

我們點選 new AnnotationConfigApplicationContext看一下他的構造方法:

public AnnotationConfigApplicationContext
(Class<?>... annotatedClasses)
{ //這個類有父類,所以會先初始化父類的構造方法,接著初始化自己的構造方法 //呼叫無參構造方法進行初始化一個讀取器和掃描器 this(); //這個方法的作用:主要是把配置類的資訊載入進工廠中 //在這裡需要你記住一個類:DefaultListableBeanFactory,後面會非常的重要 register(annotatedClasses); //例項化所有被加了元件的物件 refresh(); } 複製程式碼

我們發現這個建構函式的引數可以一次性傳多個配置類,後面程式碼中其實會遍歷annotatedClasses 這個陣列

我們看一下 this() 幹了哪些事?

	public AnnotationConfigApplicationContext() {
		//這裡也會先初始化父類的構造方法
        
        //建立一個讀取被加了註解的bean讀取器,這個讀取器到底什麼鬼,不是這節的重點,可以先忽略
        //你就知道他建立了一個讀取器就完事了
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
複製程式碼

我們回到 register(annotatedClasses);這個方法,這個方法就是本節的大哥,我們現在就要去看看,他為Spring幹了哪些髒活!

3.載入配置類

我們點選 register(annotatedClasses)

嗯....,好像沒啥用!

點選 this.reader.register(annotatedClasses); 方法

這時候,我們發現這個方法開始遍歷annotatedClasses 陣列,由此我們可以一次性寫多個配置檔案傳給構造方法的

開始遍歷annotatedClasses(注意:本次演示中,我只添加了一個配置類),呼叫 registerBean(annotatedClass);

我們這時候點選 registerBean(annotatedClass);

點選 doRegisterBean(annotatedClass,null,null);

	<T> void doRegisterBean(Class<T> annotatedClass,@Nullable Supplier<T> instanceSupplier,@Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers,BeanDefinitionCustomizer... definitionCustomizers) {
        //(1)(解析:檢視下面圖)
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
	 
        
        //這個不是重點,跳過
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
        
         //這個不是重點,跳過 instanceSupplier為null值
		abd.setInstanceSupplier(instanceSupplier);

		//(2)得到類的作用域 單例還是多例(解析:檢視下面圖)
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        
		//把類的作用域賦值給AnnotatedGenericBeanDefinition物件
		abd.setScope(scopeMetadata.getScopeName());

		//生成配置類的名稱,如果@Component沒有對應的名稱   (我沒有加名稱)
        //預設是類的小駝峰式命名稱 (所有此時beanName為springConfiguration)
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd,this.registry));

		/**
		 * (3)把AnnotatedGenericBeanDefinition物件傳進
		 * 然後獲取獲取元資料metadata物件,判斷元資料物件中是否存在lazy,DependsOn,Primary Role 等註解
		 * 如果有這些註解,則在AnnotatedGenericBeanDefinition物件中記錄
		 */
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

		//qualifiers本身傳過來的就是一個 null 值
		//如果不手動傳,永遠為空值,沒有意義
		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));
				}
			}
		}
        
		//這個不是重點
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}
        
         //(4)把abd放進去,賦值給了成員變數beanDefinition
		//把BeanName賦值進去,可以說是增強版的abd物件
		//檢視後面的程式碼發現,其實definitionHolder就只是起到一個臨時容器的作用
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd,beanName);

		//這個比較複雜,以後可以講 和本節無關
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);

		//(5)現在又把增強版的 definitionHolder 放到registry這個容器中
		//BeanDefinitionRegistry 顧名思義 就是註冊BeanDefinition的
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,this.registry);
	}
複製程式碼

1).我們檢視程式碼AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);幹了哪些事 ?

通過debug 檢視 abd 物件內容

總結:

  1. 根據指定的配置類,建立一個GenericBeanDefinition物件
  2. 這個GenericBeanDefinition物件包含了該類的一些元資訊,例如註解資訊: scope,lazy,ComponentScan等註解
  3. 這些註解儲存在 GenericBeanDefinition中的 元資料(metadata)物件中
  4. 元資料物件有一個註解集合 annotations,儲存所有的註解資訊

2).接下來檢視 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

執行完這個abd.setScope(scopeMetadata.getScopeName());方法後

3).檢視 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

點選進入

額...,這個方法好像也沒啥...

把傳進的abd物件拆開,又傳了abd物件和abd.getMetadata()元資料物件

點選 processCommonDefinitionAnnotations(abd,abd.getMetadata());

	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd,AnnotatedTypeMetadata metadata) {
		//判斷當前的類是否加了lazy註解
		AnnotationAttributes lazy = attributesFor(metadata,Lazy.class);
        
		//如果不為null,則把AnnotatedBeanDefinition中的 lazyInit 預設的false 修改為true
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
		else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(),Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}
        
		//判斷元資料物件中時候有@Primary,預設時候primary是 false,如果有則該為true
		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
        
		//判斷時候有@DependsOn註解
		AnnotationAttributes dependsOn = attributesFor(metadata,DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}

		//判斷時候有@Role註解
		AnnotationAttributes role = attributesFor(metadata,Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}
        
		//判斷時候有@Description註解
		AnnotationAttributes description = attributesFor(metadata,Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}
複製程式碼

總結:

  1. 把AnnotatedGenericBeanDefinition物件傳進去
  2. 獲取元資料metdata物件,Primary Role 等註解
  3. 如果有這些註解,則在AnnotatedGenericBeanDefinition物件中記錄

4).檢視 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd,beanName);

debug 發現

5).檢視 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,this.registry);

點選進入

public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder,BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		
		//在這裡又獲取beanName的名稱
		String beanName = definitionHolder.getBeanName();
    
		//現在把definitionHolder拆分了,又把abd物件拿出來了
		//似乎definitionHolder就只是封裝了一下,然後又給拆分,可以理解為一個臨時的容器
		registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition());

		 //這個不重要,spring當中處理別名的
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName,alias);
			}
		}
	}
複製程式碼

我們點選 registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition());

發現是一個介面,按住快捷鍵 Ctrl + Alt + B,有三個實現類,前面叫你留意的 DefaultListableBeanFactory 在這裡出現了,

選擇 DefaultListableBeanFactory

	@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 {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,"Validation of bean definition failed",ex);
			}
		}
        //檢視該bean時候在map集合中儲存過
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName,beanDefinition,existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION,now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				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()) {
				// 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;
					removeManualSingletonName(beanName);
				}
			}
     //---------------------------------------------------------------------------------------
            //前面的程式碼都是一些判斷,驗證不是重點
            //重點是這裡的程式碼,前方高能
			else {
				//在這個方法中就把 beanDefinition 儲存在 DefaultListableBeanFactory的map集合中
				//顧名思義,beanDefinitionMap就是一個儲存beanDefinition的map集合
				//在這個集合當中還有Spring當中本身已經初始好的物件
				this.beanDefinitionMap.put(beanName,beanDefinition);
				//把beanName儲存在這個list集合中
				this.beanDefinitionNames.add(beanName);
				//這個是去重的,不是重點
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}
複製程式碼

this.beanDefinitionMap.put(beanName,beanDefinition); 之前

this.beanDefinitionMap.put(beanName,beanDefinition); 之後

this.beanDefinitionNames.add(beanName); 之前

this.beanDefinitionNames.add(beanName); 之後

整個配置類的載入過程就執行完了,最後總結一下 register(annotatedClasses); 都幹了哪些事?

  1. 載入配置類的元資料 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
  2. 給abd物件設定作用域
  3. 遍歷元資料註解,判斷時候存在某註解
  4. 把配置類資訊物件儲存到 DefaultListableBeanFactory的beanDefinitionMap集合中
  5. 把配置類的名稱儲存到 DefaultListableBeanFactory的 beanDefinitionNames 集合中

4.視訊講解:

www.bilibili.com/video/av678…

視訊為自己學習的時候錄製的,也方便自己以後看

原始碼地址:

github.com/zouchangfu/… gitee.com/zouchangfu/…

寫在最後:

大二學生一枚,擠時間寫部落格不容易呀,看完順手點個贊,你的點贊是對我最大的鼓勵