劍指Spring源碼(一)

Spring,相信每一個Java開發都用過,並且是天天都在用,那強大又神祕的IoC,AOP,讓咱們的開發變得愈來愈簡單,只須要一個註解搞定一切,可是它內部究竟是什麼樣子的呢?跟着我,一塊兒探究Spring源碼把。spring

寫在前面的話:Spring項目距今已有15年左右的歷史了,是衆多Java大神們的傑做,因爲我我的水平有限,時間有限,不保證我說的所有都是正確的,可是我能夠保證每一句話都是反覆推敲,通過驗證,絕沒有複製粘貼。固然在這裏,也不可能把每一個方法都進行深層次的分析,只能把重點集中在重要的方法上,有些(實際上是絕大部分)只能採起黑盒理論,即:不去探究方法內部到底作了什麼,只大概的知道執行這個方法後發生了什麼。數組

本文中採用的Spring版本是5.0.0bash

因爲如今JavaConfig風格+註解的方式來使用Spring,是Spring官方主推的,也是如今的主流方式,因此咱們從這裏出發:數據結構

AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
複製代碼

讓咱們先來看看AnnotationConfigApplicationContext的關係圖:app

image.png

能夠看到這個關係夠複雜的,咱們如今徹底不須要特地所有記住,只要有一個大概的印象就能夠了,後面隨着源碼分析的深刻,天然而然會記住其中的一些關係。函數

建立AnnotationConfigApplicationContext對象,首先會跑到這裏:源碼分析

//根據參數類型能夠知道,其實能夠傳入多個annotatedClasses,可是這種狀況出現的比較少
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		//調用無參構造函數,會先調用父類GenericApplicationContext的構造函數
		//父類的構造函數裏面就是初始化DefaultListableBeanFactory,而且賦值給beanFactory
		//本類的構造函數裏面,初始化了一個讀取器:AnnotatedBeanDefinitionReader read,一個掃描器ClassPathBeanDefinitionScanner scanner
		//scanner的用處不是很大,它僅僅是在咱們外部手動調用 .scan 等方法纔有用,常規方式是不會用到scanner對象的
		this();
		//把傳入的類進行註冊,這裏有兩個狀況,
		//傳入傳統的配置類
		//傳入bean(雖然通常沒有人會這麼作
		//看到後面會知道spring把傳統的帶上@Configuration的配置類稱之爲FULL配置類,不帶@Configuration的稱之爲Lite配置類
		//可是咱們這裏先把帶上@Configuration的配置類稱之爲傳統配置類,不帶的稱之爲普通bean
		register(annotatedClasses);
		//刷新
		refresh();
	}
複製代碼

這個方法第一眼看上去,很簡單,無非就是三行代碼,可是這三行代碼包含了大千世界。ui

咱們先來爲構造方法作一個簡單的說明:this

  1. 這是一個有參的構造方法,能夠接收多個配置類,不過通常狀況下,只會傳入一個配置類。lua

  2. 這個配置類有兩種狀況,一種是傳統意義上的帶上@Configuration註解的配置類,還有一種是沒有帶上@Configuration,可是帶有@Component,@Import,@ImportResouce,@Service,@ComponentScan等註解的配置類,在Spring內部把前者稱爲Full配置類,把後者稱之爲Lite配置類。在本源碼分析中,有些地方也把Lite配置類稱爲普通Bean。

咱們先來看一下第一行代碼:經過this()調用此類無參的構造方法,代碼會跑到下面:

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

	//註解bean定義讀取器,主要做用是用來讀取被註解的了bean
	private final AnnotatedBeanDefinitionReader reader;

	//掃描器,它僅僅是在咱們外部手動調用 .scan 等方法纔有用,常規方式是不會用到scanner對象的
	private final ClassPathBeanDefinitionScanner scanner;

	/**
	 * Create a new AnnotationConfigApplicationContext that needs to be populated
	 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
	 */
	public AnnotationConfigApplicationContext() {
		//會隱式調用父類的構造方法,初始化DefaultListableBeanFactory

		//初始化一個Bean讀取器
		this.reader = new AnnotatedBeanDefinitionReader(this);

		//初始化一個掃描器,它僅僅是在咱們外部手動調用 .scan 等方法纔有用,常規方式是不會用到scanner對象的
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
}
複製代碼

首先映入眼簾的是reader和scanner,無參構造方法中就是對reader和scanner進行了實例化,reader的類型是AnnotatedBeanDefinitionReader,從字面意思就能夠看出它是一個 「打了註解的Bean定義讀取器」,scanner的類型是ClassPathBeanDefinitionScanner,其實這個字段並不重要,它僅僅是在咱們外面手動調用.scan方法,或者調用參數爲String的構造方法,傳入須要掃描的包名,纔會用到,像咱們這樣傳入配置類是不會用到這個scanner對象的。

AnnotationConfigApplicationContext類是有繼承關係的,會隱式調用父類的構造方法:

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	private final DefaultListableBeanFactory beanFactory;
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
}
複製代碼

這個代碼很簡單,就是初始化了DefaultListableBeanFactory。

咱們再來看看DefaultListableBeanFactory的關係圖:

image.png

DefaultListableBeanFactory是至關重要的,從字面意思就能夠看出它是一個Bean的工廠,什麼是Bean的工廠?固然就是用來生產和得到Bean的。

讓咱們把目光回到AnnotationConfigApplicationContext的無參構造方法,讓咱們看看Spring在初始化AnnotatedBeanDefinitionReader的時候作了什麼:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
	}
複製代碼

這裏的BeanDefinitionRegistry固然就是AnnotationConfigApplicationContext的實例了,這裏又直接調用了此類其餘的構造方法:

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);
	}
複製代碼

讓咱們把目光移動到這個方法的最後一行,進入registerAnnotationConfigProcessors方法:

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
		registerAnnotationConfigProcessors(registry, null);
	}
複製代碼

這又是一個門面方法,再點進去,這個方法的返回值Set,可是上游方法並無去接收這個返回值,因此這個方法的返回值也不是很重要了,固然方法內部給這個返回值賦值也不重要了。因爲這個方法內容比較多,這裏就把最核心的貼出來,這個方法的核心就是註冊Spring內置的多個Bean:

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));
}
複製代碼
  1. 判斷容器中是否已經存在了ConfigurationClassPostProcessor Bean

  2. 若是不存在(固然這裏確定是不存在的),就經過RootBeanDefinition的構造方法得到ConfigurationClassPostProcessor的BeanDefinition,RootBeanDefinition是BeanDefinition的子類:

image.png

  1. 執行registerPostProcessor方法,registerPostProcessor方法內部就是註冊Bean。

固然這裏註冊其餘Bean也是同樣的流程。

BeanDefinition是什麼,顧名思義,它是用來描述Bean的,裏面存放着關於Bean的一系列信息,好比Bean的做用域,Bean所對應的Class,是否懶加載,是否Primary等等,這個BeanDefinition也至關重要,咱們之後會經常和它打交道。

registerPostProcessor方法:

private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(beanName, definition);
		return new BeanDefinitionHolder(definition, beanName);
	}
複製代碼

這方法爲BeanDefinition設置了一個Role,ROLE_INFRASTRUCTURE表明這是spring內部的,並不是用戶定義的,而後又調用了registerBeanDefinition方法,再點進去,Oh No,你會發現它是一個接口,沒辦法直接點進去了,首先要知道registry實現類是什麼,那麼它的實現是什麼呢?答案是DefaultListableBeanFactory:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
	}
複製代碼

這又是一個門面方法,再點進去,核心在於下面兩行代碼:

//beanDefinitionMap是Map<String, BeanDefinition>,
//這裏就是把beanName做爲key,ScopedProxyMode做爲value,推到map裏面
this.beanDefinitionMap.put(beanName, beanDefinition);

//beanDefinitionNames就是一個List<String>,這裏就是把beanName放到List中去
this.beanDefinitionNames.add(beanName);
複製代碼

從這裏能夠看出DefaultListableBeanFactory就是咱們所說的容器了,裏面放着beanDefinitionMap,beanDefinitionNames,beanDefinitionMap是一個hashMap,beanName做爲Key,beanDefinition做爲Value,beanDefinitionNames是一個集合,裏面存放了beanName。打個斷點,第一次運行到這裏,監視這兩個變量:

image.png
image.png

DefaultListableBeanFactory中的beanDefinitionMap,beanDefinitionNames也是至關重要的,之後會常常看到它,最好看到它,第一時間就能夠反應出它裏面放了什麼數據

這裏僅僅是註冊,能夠簡單的理解爲把一些原料放入工廠,工廠尚未真正的去生產。

上面已經介紹過,這裏會一連串註冊好幾個Bean,在這其中最重要的一個Bean(沒有之一)就是BeanDefinitionRegistryPostProcessor Bean。

ConfigurationClassPostProcessor實現BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor接口又擴展了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor是Spring的擴展點之一,ConfigurationClassPostProcessor是Spring極爲重要的一個類,必須緊緊的記住上面所說的這個類和它的繼承關係。

image.png

除了註冊了ConfigurationClassPostProcessor,還註冊了其餘Bean,其餘Bean也都實現了其餘接口,好比BeanPostProcessor接口。

BeanPostProcessor接口也是Spring的擴展點之一。

至此,實例化AnnotatedBeanDefinitionReader reader分析完畢。

因爲常規使用方式是不會用到AnnotationConfigApplicationContext裏面的scanner的,因此這裏就不看scanner是如何被實例化的了。

把目光回到最開始,再分析第二行代碼:

register(annotatedClasses);
複製代碼

這裏傳進去的是一個數組,最終會循環調用以下方法:

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
		//AnnotatedGenericBeanDefinition能夠理解爲一種數據結構,是用來描述Bean的,這裏的做用就是把傳入的標記了註解的類
		//轉爲AnnotatedGenericBeanDefinition數據結構,裏面有一個getMetadata方法,能夠拿到類上的註解
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

		//判斷是否須要跳過註解,spring中有一個@Condition註解,當不知足條件,這個bean就不會被解析
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(instanceSupplier);

		//解析bean的做用域,若是沒有設置的話,默認爲單例
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());

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

		//解析通用註解,填充到AnnotatedGenericBeanDefinition,解析的註解爲Lazy,Primary,DependsOn,Role,Description
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

		//限定符處理,不是特指@Qualifier註解,也有多是Primary,或者是Lazy,或者是其餘(理論上是任何註解,這裏沒有判斷註解的有效性),若是咱們在外面,以相似這種
		//AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);常規方式去初始化spring,
		//qualifiers永遠都是空的,包括上面的name和instanceSupplier都是一樣的道理
		//可是spring提供了其餘方式去註冊bean,就可能會傳入了
		if (qualifiers != null) {
			//能夠傳入qualifier數組,因此須要循環處理
			for (Class<? extends Annotation> qualifier : qualifiers) {
				//Primary註解優先
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				//Lazy註解
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				//其餘,AnnotatedGenericBeanDefinition有個Map<String,AutowireCandidateQualifier>屬性,直接push進去
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}

		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}

		//這個方法用處不大,就是把AnnotatedGenericBeanDefinition數據結構和beanName封裝到一個對象中
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

		//註冊,最終會調用DefaultListableBeanFactory中的registerBeanDefinition方法去註冊,
		//DefaultListableBeanFactory維護着一系列信息,好比beanDefinitionNames,beanDefinitionMap
		//beanDefinitionNames是一個List<String>,用來保存beanName
		//beanDefinitionMap是一個Map,用來保存beanName和beanDefinition
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}
複製代碼

在這裏又要說明下,以常規方式去註冊配置類,此方法中除了第一個參數,其餘參數都是默認值。

  1. 經過AnnotatedGenericBeanDefinition的構造方法,得到配置類的BeanDefinition,這裏是否是似曾類似,在註冊ConfigurationClassPostProcessor類的時候,也是經過構造方法去得到BeanDefinition的,只不過當時是經過RootBeanDefinition去得到,如今是經過AnnotatedGenericBeanDefinition去得到。

    image.png

  2. 判斷需不須要跳過註冊,Spring中有一個@Condition註解,若是不知足條件,就會跳過這個類的註冊。

  3. 而後是解析做用域,若是沒有設置的話,默認爲單例。

  4. 得到BeanName。

  5. 解析通用註解,填充到AnnotatedGenericBeanDefinition,解析的註解爲Lazy,Primary,DependsOn,Role,Description。

  6. 限定符處理,不是特指@Qualifier註解,也有多是Primary,或者是Lazy,或者是其餘(理論上是任何註解,這裏沒有判斷註解的有效性)。

  7. 把AnnotatedGenericBeanDefinition數據結構和beanName封裝到一個對象中(這個不是很重要,能夠簡單的理解爲方便傳參)。

  8. 註冊,最終會調用DefaultListableBeanFactory中的registerBeanDefinition方法去註冊:

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

		//獲取beanName
		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();

		//註冊bean
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
                
                //Spring支持別名
		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
複製代碼

這個registerBeanDefinition是否是又有一種似曾類似的感受,沒錯,在上面註冊Spring內置的Bean的時候,已經解析過這個方法了,這裏就不重複了,此時,讓咱們再觀察下beanDefinitionMap beanDefinitionNames兩個變量,除了Spring內置的Bean,還有咱們傳進來的Bean,這裏的Bean固然就是咱們的配置類了:

image.png
image.png

到這裏註冊配置類也分析完畢了。

你們能夠看到其實到這裏,Spring尚未進行掃描,只是實例化了一個工廠,註冊了一些內置的Bean和咱們傳進去的配置類,真正的大頭是在第三行代碼:

refresh();
複製代碼

不過,這就是下一章的內容了。

相關文章
相關標籤/搜索