SpringIOC原理分析

幻_發表於2019-06-26

寫在前面

我對Spring原理的理解處於“點到為止”的狀態:對於主線流程不太重要的邏輯跳過,或者只關注它做了什麼。

學習Spring原始碼查詢了很多資料,分享幾篇大佬寫的文章,對我Spring的學習起到很大幫助

Spring IOC原始碼分析,是以ClassPathXmlApplicationContext為例

學習Spring原始碼建議搭建Spring-framemwork原始碼環境(這是一個比較麻煩的過程,可能遇到各種問題,需要有耐心..),新建個Module打斷點一步步除錯。

舉個例子,這是Spring的.class反編譯的結果,不但沒有註釋,可讀性也很差。

SpringIOC原理分析

從細節來看不同ApplicationContext生命週期略有不同,以AnnotationConfigApplicationContext和ClassPathXmlApplicationContext為例,拋開Bean的解析邏輯,比如他們倆建立BeanFactory的時機也不一樣。

這篇文章我主要以spring-framework5.1.7的AnnotationConfigApplicationContext為例分析。

寫這篇文章花了很多時間,如有錯誤,還請批評指正。

分析Spring原始碼是一個漫長的過程,如果在某個節點卡住,不妨先放一放,過段時間回頭再看沒準會茅塞頓開。另外Spring某些知識點、特殊類都可以百度一下,這些知識點的集合構成了Spring原理。

Spring中的一些重要的類及概念

在解析原始碼之前,需要先弄清楚Spring中比較重要的類,在原始碼中可能經常遇到,如果不清楚是做什麼的會很懵,這塊有個大致印象即可。

ApplicationContext

ApplicationContext就是載入Spring容器的入口,Spring的一切從這裡開始。

基於載入配置方式的不同,常見的有:

AnnotationConfigApplicationContext

基於註解獲取配置也是本文會詳細說明的。

ClassPathXmlApplicationContext、FileSystemXmlApplicationContext

基於XML獲取配置,指定配置檔案路徑來獲取配置。

XmlWebApplicationContext

在SpringBoot以前,我們的Web應用要配置Spring,通常是在web.xml配置listener和applicationContext.xml

<listener>  
     <listener-class>org.springframework.web.context.ContextLoaderListener
     </listener-class>  
</listener> 
<context-param>  
    <param-name>contextConfigLocation</param-name>  
    <param-value>classpath:applicationContext.xml</param-value>  
</context-param> 
複製程式碼

這時web應用依據載入web.xml的順序,ContextLoaderListener監聽到ServletContext載入事件,如果跟蹤原始碼最終預設會取到 Spring內建如下配置

SpringIOC原理分析
為我們建立一個XmlWebApplicationContext例項。

繼承結構

SpringIOC原理分析

另外從繼承結構可以看出,Xml和Annotation在AbstractApplicationContext處開始是兩個分支,其實就是由於繼承結構的不同,在容器建立的一些節點上,執行的是同一個介面方法的不同例項方法,從而一些實現邏輯略有不同。這裡先有個大致印象就行。

BeanDefinition

就是用來描述Bean定義的類。在Java中每個類都有個Class物件,類似的,Spring中每個我們配置的Bean都有個BeanDefinition物件。 比如Bean對應的類、是否懶載入、作用域等都在這裡描述。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    
	// ... 簡單擷取一部分
	
	
	// 設定 Bean 的類名稱,將來是要通過反射來生成例項的
	void setBeanClassName(@Nullable String beanClassName);

	// 獲取 Bean 的類名稱
	@Nullable
	String getBeanClassName();

	// scope
	void setScope(@Nullable String scope);

	// scope
	@Nullable
	String getScope();

	// 懶載入
	void setLazyInit(boolean lazyInit);

	// 是否懶載入
	boolean isLazyInit();

	// depends-on="" 屬性設定的值。
	// @DependsOn
	void setDependsOn(@Nullable String... dependsOn);

	// @DependsOn
	@Nullable
	String[] getDependsOn();

	// 設定該 Bean 是否可以注入到其他 Bean 中,只對根據型別注入有效,
	// 如果根據名稱注入,即使這邊設定了 false,也是可以的
	void setAutowireCandidate(boolean autowireCandidate);

	// 該 Bean 是否可以注入到其他 Bean 中
	boolean isAutowireCandidate();

	// @Primary
	void setPrimary(boolean primary);

	// 是否是 primary
	boolean isPrimary();

	// FactoryBean
	void setFactoryBeanName(@Nullable String factoryBeanName);

	// FactoryBean
	@Nullable
	String getFactoryBeanName();

	// ... 後面太長就不寫了

}
複製程式碼

BeanFactory

BeanFactory就是生產Bean的工廠。BeanFactory的最終目的就是為我們產生Bean例項,只不過在產生Bean例項之前需要解析註解或XML,產生BeanDefinition並註冊到BeanFactory。我們常說的Spring容器中的Bean,一方面是指Bean例項,一方面也是指Bean定義,我覺得都不算錯。

Spring容器

上面提到BeanFactory,可能會聯想到Spring容器。

巨集觀上看,BeanFactory、ApplicationContext、包括後面會提到的DefaultListableBeanFactory、DefaultSingletonBeanRegistry,都可以算作Spring容器,或者他們的集合是Spring容器。這個容器一方面儲存了Bean例項,另一方面也儲存了Bean的定義。

微觀上看,容器是儲存我們Bean定義的是DefaultListableBeanFactory的一個map屬性、儲存Bean例項的是DefaultSingletonBeanRegistry的一個map屬性,都是map。

DefaultListableBeanFactory

我們具體操作的BeanFactory例項就是DefaultListableBeanFactory型別的。 這裡列出DefaultListableBeanFactory兩個重要的屬性,就是用來儲存BeanDefinition的容器。

//  bean定義的對映,以name為key
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

// bean定義名字List,以註冊順序排序
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
複製程式碼

FactoryBean

通過實現FactoryBean,會為我們例項化兩個Bean。

一個是當前Bean,只不過name前加了個&,標識出這個是FactoryBean的例項

一個是基於介面方法返回的例項來為我們建立Bean例項。

FactoryBean可以將一些複雜依賴的類合併成一個物件返回,可以用於封裝。

典型應用:mybatis的SqlSessionFactoryBean

使用示例:

@Component
public class MyFactoryBean implements FactoryBean {

	@Override
	public Object getObject() throws Exception {
		return new User();
	}

	@Override
	public Class<?> getObjectType() {
		return User.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
}
複製程式碼
public class User {

	private String id;

	private String name;

	public User(){
		id = "001";
		name = "lby";
	}

}
複製程式碼

功能驗證

public class SpringTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		User u = (User) context.getBean("myFactoryBean");
		MyFactoryBean myFactoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");
	}
	
}
複製程式碼

輸出結果

SpringIOC原理分析

BeanPostProcessor

後置處理器,他有兩個方法postProcessBeforeInitialization和postProcessAfterInitialization。

Bean在例項化之後、初始化前後會執行。

這只是個籠統的說法。所謂初始化就是呼叫Spring的InitMethods方法。

初始化Spring的Bean有三種方式:

init-method,可以在XML裡配置也可以在java config裡配置

實現InitializingBean介面

@PostConstruct註解,解析執行該註解的本身就是一個BeanPostProcessor,所以Spring的InitMethods不包括@PostConstruct

看過Bean的例項化部分的原始碼會發現,Bean在例項化之後這三種初始化方式的執行順序是

@PostConstruct -> InitializingBean -> init-method

解析@PostConstruct註解的是CommonAnnotationBeanPostProcessor後置處理器

而後置處理器是在InitMethods的前後執行。而InitMethods裡的執行順序是先執行InitializingBean後執行init-method,所以最終是這個執行順序。

不過按現在程式設計風格,一般都用@PostConstruct,另外兩個不常用

典型應用:CommonAnnotationBeanPostProcessor,就是解析@PostConstruct的後置處理器

使用示例:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("myDao".equals(beanName)) {
            System.out.println("BeforeInitialization " + beanName + "...");
        }
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("myDao".equals(beanName)) {
            System.out.println("AfterInitialization " + beanName + "...");
        }
        return null;
    }
}
複製程式碼

BeanFactoryPostProcessor

後置處理器,BeanFactoryPostProcessor可以在bean例項化之前可以讀取bean的定義並修改它。同時可以定義多個BeanFactoryPostProcessor,通過設定@Order來確定各個BeanFactoryPostProcessor執行順序

典型應用:ConfigrationClassPostProcessor,這是解析Bean的核心,後面會有解釋

使用示例

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) 
    throws BeansException {
        BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("myService");
        bd.setBeanClassName("com.spring.bean.MyDao");
    }
}
複製程式碼

這裡我們將myService的class由com.spring.bean.MyService改為com.spring.bean.MyDao,

public class SpringTest {

    public static void main(String[] args){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        ClassPathXmlApplicationContext context1 = new ClassPathXmlApplicationContext();
        MyDao myDao = (MyDao)context.getBean("myDao");
        MyDao myService = (MyDao)context.getBean("myService");
        System.out.println(myService.toString());
    }

}
複製程式碼

再將myService的例項輸出出來,結果已經變成com.spring.bean.MyDao的例項

SpringIOC原理分析

BeanDefinitionRegistryPostProcessor

後置處理器,它繼承了BeanFactoryPostProcessor,可以認為是特別的BeanFactoryPostProcessor,通過實現BeanDefinitionRegistryPostProcessor可以介入容器的初始化過程,他的呼叫時機與BeanFactoryPostProcessor一樣,只不過優先於BeanFactoryPostProcessor呼叫。

典型應用:ConfigrationClassPostProcessor

使用示例:

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("MyBeanDefinitionRegistryPostProcessor  -> postProcessBeanFactory");
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		String[] beanDefinitionNames = registry.getBeanDefinitionNames();
		for (String name : beanDefinitionNames) {
			System.out.println("MyBeanDefinitionRegistryPostProcessor  -> " + name);
		}
	}
}
複製程式碼

SpringIOC原理分析

可以看出BeanDefinitionRegistryPostProcessor要先於BeanFactoryPostProcessor執行,postProcessBeanDefinitionRegistry方法要先於postProcessBeanFactory執行。

至於為什麼是這個結果,如果看了原始碼,實際上Spring內部的呼叫順序就是這樣。

ConfigurationClassPostProcessor

它繼承了BeanDefinitionRegistryPostProcessor,所以他也是後置處理器。在Spring解析Bean的過程中,他是最重要的也是第一個執行的BeanFactoryPostProcessor,我們的自定義的@Compent、@Bean、@Import等都是由這個類開始解析並註冊的。

ImportSelector

是一個介面,功能上可以簡單把它理解為動態版的@Import

典型應用:@EnableTransactionManagement

使用示例:

public class MyImport {

    public void printSomething() {
        System.out.println("MyImport");
    }

}

public class MyImportSelector implements ImportSelector {

	public void printSomething(){
		System.out.println("MyImportSelector");
	}

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		// 當然這裡也可以依賴annotationMetadata的內容,執行一些特殊邏輯
		// annotationMetadata可以獲得打上@Import類的後設資料資訊
		return new String[]{MyImportSelectorAAA.class.getName(), 
		MyImportSelectorBBB.class.getName()};
	}
}

public class MyImportSelectorAAA {

    public void printSomething(){
        System.out.println("MyImportSelectorAAA");
    }

}

public class MyImportSelectorBBB {

    public void printSomething(){
        System.out.println("MyImportSelectorAAA");
    }

}
複製程式碼

JavaConfig

@Configuration
@ComponentScan("com.lby")
@Import({MyImport.class, MyImportSelector.class})
public class AppConfig {

}
複製程式碼

功能驗證

public class SpringTest {

	public static void main(String[] args){
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		MyImport myImport = (MyImport)context.getBean(MyImport.class.getName());
		myImport.printSomething();
		MyImportSelectorAAA myImportSelectorAAA =
		(MyImportSelectorAAA)context.getBean(MyImportSelectorAAA.class.getName());
		myImportSelectorAAA.printSomething();
		MyImportSelectorBBB myImportSelectorBBB =
		(MyImportSelectorBBB)context.getBean(MyImportSelectorBBB.class.getName());
		myImportSelectorBBB.printSomething();
	}

}
複製程式碼

輸出結果

SpringIOC原理分析
可以看到上面Imoprt的類已經成功被例項化。

MyImport是普通類,MyImportSelector實現了ImportSelector介面,重寫selectImports方法返回MyImportSelectorAAA、MyImportSelectorBBB

@Import(MyImport.class)是直接將引入的MyImport註冊到BeanFactory

@Import(MyImportSelector.class)則是將MyImportSelectorAAA、MyImportSelectorBBB註冊到BeanFactory,但MyImportSelector本身不會註冊。

ImportBeanDefinitionResgistor

典型應用:@EnableAspectAutoProxy、@MapperScan

ApplicationContextAware

IOC容器的初始化

IOC容器的初始化我這裡粗略的分成三步走:

1、BeanFactory的準備工作

2、Bean的解析

3、Bean的例項化

這三步可以說一步比一步難,先有個心理準備。

BeanFactory的準備工作

從AnnotationConfigApplicationContext開始,走進SpringIOC容器

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
複製程式碼
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
	// 構造方法
	this();
	// 註冊類,所謂註冊,把它理解為把這個bean放到容器裡即可
	register(annotatedClasses);
	// 重新整理容器的內容,核心方法
	// 不論是AnnotationConfigApplicationContext還是ClassPathXmlApplicationContext都會走這同一個方法
	refresh();
}
複製程式碼

我們先看構造方法,

public AnnotationConfigApplicationContext() {
    // 重點,從類名字上可以看出是註解式bean定義讀取器
    this.reader = new AnnotatedBeanDefinitionReader(this);
    // 不是重點,忽略
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}
複製程式碼

呼叫子類構造方法前會呼叫父類構造方法。AnnotationConfigApplicationContext繼承鏈路上有很多類,我們重點關注GenericApplicationContext的構造方法

public GenericApplicationContext() {
    // 例項化了一個BeanFactory
    this.beanFactory = new DefaultListableBeanFactory();
}
複製程式碼

可以看到AnnotationConfigApplicationContext的第一步就是通過構造方法為我們例項化一個空的BeanFactory即DefaultListableBeanFactory例項,我們常說的BeanFactory一般就是DefaultListableBeanFactory例項。

我們看一下DefaultListableBeanFactory的成員屬性

//  是否允許bean覆蓋
private boolean allowBeanDefinitionOverriding = true;

// 是否允許即使是懶載入的Bean立刻載入
private boolean allowEagerClassLoading = true;

// 比較器
@Nullable
private Comparator<Object> dependencyComparator;

// 用於檢查一個類定義是否有自動注入的解析器
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();

// 依賴的類與例項的map對映
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

//  bean定義的對映,以name為key
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

//  單例和非單例bean名稱對映,以型別為key
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

//  單例的bean名稱對映,以型別為key
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

// bean定義名字List,以註冊順序排序
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

// 人工註冊的單例bean定義的有序Set,以註冊順序排序
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

// 快取bean定義名字的陣列
@Nullable
private volatile String[] frozenBeanDefinitionNames;

// 是否允許bean定義的後設資料被快取,以用於所有的bean
private volatile boolean configurationFrozen = false;
複製程式碼

可以說DefaultListableBeanFactory例項就是我們的BeanDefinition容器。更具體點就是beanDefinitionMap。

回到這裡

public AnnotationConfigApplicationContext() {
    // 重點,從類名字上可以看出是註解式bean定義讀取器
    this.reader = new AnnotatedBeanDefinitionReader(this);
    // 不是重點,忽略
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}
複製程式碼

呼叫父類的構造方法生成DefaultListableBeanFactory物件之後,重點就是

this.reader = new AnnotatedBeanDefinitionReader(this);
複製程式碼

順著呼叫鏈路一路下鑽,只挑重點,執行到了AnnotationConfigUtils類的registerAnnotationConfigProcessors方法

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
複製程式碼

這裡BeanDefinitionRegistry型別的registry就是我們的當前例項。前面通過構造方法例項化了GenericApplicationContext物件,而GenericApplicationContext實現了BeanDefinitionRegistry介面,相當於BeanDefinitionRegistry的子類。

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) {
	// 不是重點
	// 其實就是為我們返回當前GenericApplicationContext例項(registry)的DefaultListableBeanFactory型別beanFactory屬性
	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {// 不是重點,前面剛例項化的DefaultListableBeanFactory,這裡必不為空
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			// 設定比較器,往後看就知道排序器是用來幹啥的了
			// 其實這裡就算不初始化比較器也沒事,後面比較的地方也會有預設的比較器
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)){
			// 設定自動注入的解析器
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}
	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		// 註冊ConfigurationClassPostProcessor後置處理器
		// ConfigurationClassPostProcessor是非常重要的類
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		// 註冊AutowiredAnnotationBeanPostProcessor後置處理器
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		// JSR-250一種規範,需要支援@Resource、@PostConstruct以及@PreDestroy註解
		// CommonAnnotationBeanPostProcessor後置處理器就是處理這些註解的
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		// JPA支援,註冊  PersistenceAnnotationProcessor後置處理器
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			...
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		// 註冊 EventListenerProcessor後置處理器
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}
	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		// 註冊 EventListenerFactory
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}
	return beanDefs;
}
複製程式碼

registerAnnotationConfigProcessors主要就是為我們註冊了一些Spring預設的後置處理器。這裡所謂的註冊,主要就是將這些後置處理器轉換成BeanDefinition物件,並存入前面我們例項化的Bean工廠中(DefaultListableBeanFactory物件的beanDefinitionMap、beanDefinitionNames屬性)。

此處註冊了這幾個後置處理器

ConfigurationClassPostProcessor

AutowiredAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor

PersistenceAnnotationProcessor

EventListenerProcessor

EventListenerFactory

回到我們前面AnnotationConfigApplicationContext的構造方法

// AnnotationConfigApplicationContext類的AnnotationConfigApplicationContext(Class<?>... annotatedClasses)
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
	// 構造方法
	this();
	// 註冊類,所謂註冊,把它理解為把這個bean放到容器裡即可
	register(annotatedClasses);
	// 重新整理,核心方法
	// 不論是AnnotationConfigApplicationContext還是ClassPathXmlApplicationContext都會走這同一個方法
	// AnnotationConfigApplicationContext繼承自GenericApplicationContext
	// GenericApplicationContext只能refresh一次 否則會拋異常
	refresh();
}
複製程式碼

無參構造方法this主要流程已經走完,register(annotatedClasses)其實就是把我們傳入的Bean,比如將我們的JavaConfig註冊到BeanFactory中而已。

至此,三步走中最簡單的一步:BeanFactory準備工作,大致流程已經走完。

總結下,核心邏輯就是為我們例項化BeanFactory,並將內建的幾個重要的後置處理器註冊到BeanFactory中。這裡算是個入門,重中之重是後面的refresh方法。

Bean的解析

檢視refresh方法

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 不是重點,容器重新整理前的準備工作,記錄下容器的啟動時間、標記“已啟動”狀態、close狀態等。
		prepareRefresh();
		// 獲取我們的beanFactory,這裡Annotation版和XML版是不同的實現
		// Annotation版,因為我們在例項化AnnotationConfigApplicationContext時已經建立了beanFactory
		// 所以這裡的輯僅僅是獲取而已
		// 但如果是XML版,是在這個環節建立beanFactory
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// BeanFactory的準備工作
		// 主要是加了兩個後置處理器:ApplicationContextAwareProcessor,ApplicationListenerDetector
		// 一些依賴的略,註冊一些內建bean等
		// 注意這裡是新增後置處理器是add到BeanFactory(AbstractBeanFactory類的beanPostProcessors屬性)
		// 而前面我們在例項化BeanFactory時是註冊了幾個後置處理器,將後置處理器轉換為BeanDefinition放入BeanFactory中
		// 這裡沒必要太糾結
		// 當前只是Spring將一分部後置處理器轉換成BeanDefine註冊到BeanFactory,一部分是直接add到BeanFactory
		// 後面都會統一add到BeanFactory的beanPostProcessors屬性
		prepareBeanFactory(beanFactory);
		try {
			// 這裡現在是空方法,實際上是提供給子類的擴充套件點,子類可以重寫該方法。
			postProcessBeanFactory(beanFactory);
			// 重點,執行BeanFactoryProcessor各個實現類的 postProcessBeanFactory方法
			// 執行內建的和我們手動新增的BeanFactoryPostProcessors
			// 手動新增的是需要手動呼叫annotationConfigApplicationContext.addBeanFactoryPostProcessor來新增
			// 那內建的呢?回想我們前面BeanFactory初始化spring為我們加了很多後置處理器
			// 其中ConfigurationClassPostProcessor就是繼承自BeanFactoryPostProcessor
			// ConfigurationClassPostProcessor是重點!
			invokeBeanFactoryPostProcessors(beanFactory);
			// 註冊 BeanPostProcessor 的實現類
			// 所有的BeanPostProcessor統一add到BeanFactory的beanPostProcessors屬性,準備執行
			registerBeanPostProcessors(beanFactory);
			// 不是重點,忽略。
			initMessageSource();
			// 初始化當前 ApplicationContext 的事件廣播器
			initApplicationEventMulticaster();
			// 和上面postProcessBeanFactory類似,也是空方法,提供給子類的擴充套件點
			onRefresh();
			// 不是重點。註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。
			registerListeners();
			// 重點,初始化所有的 singleton beans
			finishBeanFactoryInitialization(beanFactory);
			// 最後,廣播事件,ApplicationContext 初始化完成
			finishRefresh();
		}
		catch (BeansException ex) {
			...
		}
		finally {
			...
		}
	}
}
複製程式碼

refresh是巨集觀上的處理流程,我們重點關注這幾個方法,其他的先忽略:

  • ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  • invokeBeanFactoryPostProcessors(beanFactory);
  • registerBeanPostProcessors
  • finishBeanFactoryInitialization(beanFactory);

這裡我們劃分一下,前兩個方法屬於Bean的解析過程,後兩個方法屬於Bean的例項化過程。

obtainFreshBeanFactory()

順著呼叫鏈路會執行到AbstractApplicationContext類的refreshBeanFactory方法。

SpringIOC原理分析
refreshBeanFactory是抽象方法,不同的例項執行不同的實現。

回頭看上面ApplicationContext的繼承結構, 因為我們的AnnotationConfigApplicationContext是GenericApplicationContext的子類,所以應該走GenericApplicationContext類的refreshBeanFactory方法,他的邏輯比較簡單,就是獲取前面BeanFactory準備工作例項化的DefaultListableBeanFactory例項。

而如果是ClassPathXmlApplicationContext,會執行AbstractRefreshableApplicationContext的refreshBeanFactory方法,它的DefaultListableBeanFactory例項是在這裡建立的,這裡就不詳細闡述了。而這也是Annotation和XML區別之一。

invokeBeanFactoryPostProcessors(beanFactory)

只看主線,順著呼叫鏈路會執行到如下方法

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	// 一個用於判斷的容器而已,凡是已經執行過的後置處理器都放入這裡
	Set<String> processedBeans = new HashSet<>();
	// 我們的BeanFactory實際是DefaultListableBeanFactory例項
	// 而DefaultListableBeanFactory實現了BeanDefinitionRgistry,所以是True
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		// 用來存放BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		// 用來存放BeanDefinitionRegistryPostProcessor
		// BeanDefinitionRegistryPostProcessor繼承了用來存放BeanFatoryPostProcessor
		// 這兩個集合就是做了個區分,後面邏輯需要
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
		// 為我們手動新增的beanFactoryPostProcessors做區分存入上面兩個集合裡
		// 除了用註解,我們可以這麼新增BeanFactoryPostProcessor 
		// context.addBeanFactoryPostProcessor(newMyBeanDefinitionRegistryPostProcessor());
		// 不過此處一般情況下為空,我覺得可以跳過
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}

		// 就是個臨時變數而已,後面的邏輯共用這個變數
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
		// 下面方法過長,我們劃分一下
		// 從這開始算是第一步,執行實現了PriorityOrdered介面的BeanDefinitionRegistrPostProcessor
		
		// 首先,呼叫實現PriorityOrdered的BeanDefinitionRegistryPostProcessors
		// PriorityOrdered即優先排序,是個介面,繼承自Ordered介面
		// 而ConfigurationClassPostProcessor實現了PriortyOrdered介面
		// Ordered介面就是返回數量而已,用於排序,從而影響後置處理器的執行順序,其實我們理解為一個標記介面即可
		// 就是從我們的beanFactory的beanDefinitionNames中找到型別是BeanDefinitionRegistryPostProcessor的後置處器
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		// 當前postProcessorNames中只有ConfigurationClassPostProcessor
		// 因為前面註冊的幾個後置處理器只有ConfigurationClassPostProcessor是BeanDefinitionRegistryPostProcesor
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				// 返回一個ConfigurationClassPostProcessor例項放入currentRegistryProcessors中
				// beanFactory.getBean為我們返回例項,是個很重要的方法,這個之後詳說
				// 這裡看到在真正給所有的Bean例項化前,實際上已經有Spring內建處理器先例項化了
				currentRegistryProcessors.add(
				beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		// 不是重點,可以跳過
		// 就是給currentRegistryProcessors排序當前我們這裡只有一個ConfigurationClassPostProcessor例項
		// 其實裡面的實現很簡單,就是基於order的值排序
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		// BeanDefinitionRegistryPostProcessors的實現都放這裡
		registryProcessors.addAll(currentRegistryProcessors);
		// 執行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		// 清空
		currentRegistryProcessors.clear();
		// 從這裡算是第二步,執行實現了Ordered介面且前面未執行過的BeanDefinitionRegistryPostProcessor
		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
		// 再次從我們的beanFactory的beanDefinitionNames中找到型別是BeanDefinitionRegistryPostProcessor的後置處器
		// 又獲取一次,前面其實剛獲取到一次,引數一模一樣,之所以又取出一遍,因為前面執行過後置處理器,可能有變動
		postProcessorNames = beanFactory.
		getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true,false);
		for (String ppName : postProcessorNames) {
			// 獲取未處理的且實現Ordered介面的後置處理器
			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
				currentRegistryProcessors.add(
				beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		// BeanDefinitionRegistryPostProcessor的實現都放入registryProcessors
		registryProcessors.addAll(currentRegistryProcessors);
		// 執行我們自定義的BeanDefinitionRegistryPostProcessor
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		// 清空
		currentRegistryProcessors.clear();
		// 這裡算第三步,執行剩餘的BeanDefinitionRegistryPostProcessor
		// 也就是沒有實現Ordered介面的BeanDefinitinRegistryPostProcessor
		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		// 最後,呼叫所有其他BeanDefinitionRegistryPostProcessors
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			postProcessorNames = 
			beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName)) {
					currentRegistryProcessors.add(
					beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
					reiterate = true;
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
		}
		// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
		// 現在,呼叫到目前為止處理的所有處理器的postProcessBeanFactory回撥
		// 就是執行BeanFactoryPostProcessors的回撥方法,前面都是執行BeanDefinitionRegistryPostProcessor的回撥
		// 到這其實就能明白前面為什麼要區分registryProcessors,regularPostProcessors
		// 其實就是做了一個區分而已,然後統一呼叫postProcessBeanFactory回撥
		// regularPostProcessor表示未繼承BeanDefinitionRegistryPostProcessor
		// registryProcessors表示繼承了BeanDefinitionRegistryPostProcessor,只有我們自定義add的這裡才會有
		// 前面幾個步驟只執行了BeanDefinitionRegistryPostProcessor的回撥
		// 但還沒有執行BeanFactoryPostProcessor的回撥,此處執行
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}
	else { // 跳過吧,不確定什麼情況會走這條線
		// Invoke factory processors registered with the context instance.
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}

	// 前面取的是實現BeanDefinitionRegistryPostProcessor的後置處理器,這裡獲取實現BeanFactoryPostProcessor的後處理器
	String[] postProcessorNames =
			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

	// 以下3個List用於區分而已:實現PriorityOrdered的、實現Ordered、未實現的後置處理器
	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (processedBeans.contains(ppName)) {
			// skip - already processed in first phase above
			// 前面執行過的跳過
		}
		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// 這裡跟前面處理BeanDefinitionRegistryPostProcessor類似也分三步走
	// 第一步執行實現PriorityOrdered的
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	// 第二步執行實現Ordered
	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

	// 第三步執行未排序的
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	for (String postProcessorName : nonOrderedPostProcessorNames) {
		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
	// Clear cached merged bean definitions since the post-processors might have
	// modified the original metadata, e.g. replacing placeholders in values...
	// 存疑
	beanFactory.clearMetadataCache();
}
複製程式碼

invokeBeanFactoryPostProcessors這個方法雖然很長,但沉下心來慢慢看,其實很簡單,而且執行步驟相似。

總結下該方法做的事情,就是回撥BeanFactoryPostProcessors、BeanDefinitionRegistryPostProcessor,也就是我們前面提到的其中兩個後置處理器。只不過這些後置處理器的執行順序有個規則:

1、先執行實現PriorityOrdered介面的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,其實只有ConfigurationClassPostProcessor,這也是非常重要的類,可以說他是開始解析Bean的入口,ConfigurationClassPostProcessor會掃描Bean並解析註冊到BeanFactory

2、執行實現Ordered介面的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法

3、執行剩餘的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法

4、執行實現PriorityOrdered介面的BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor的postProcessBeanFactory方法

5、執行實現Ordered介面的BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor的postProcessBeanFactory方法

6、執行剩餘的BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor的postProcessBeanFactory方法

後續的解析邏輯實際上就是基於這幾個後置處理器是怎麼解析的。我們主要分析ConfigurationClassPostProcessor。

ConfigurationClassPostProcessor

前面我們分析過BeanDefinitionRegistryPostProcessor的執行順序,ConfigurationClassPostProcessor實現了BeanDefinitionRegistryPostProcessor,是第一個被執行的後置處理器,他重寫了兩個方法postProcessBeanDefinitionRegistry和postProcessBeanFactory。

按照我們前面分析的執行過程,ConfigurationClassPostProcessor作為BeanDefinitionRegistryPostProcessor的子類先執行法postProcessBeanDefinitionRegistry方法,當所有的法postProcessBeanDefinitionRegistry方法執行完畢之後,ConfigurationClassPostProcessor作為BeanFactoryPostProcessor的子類執行postProcessBeanFactory方法。

我們先看postProcessBeanDefinitionRegistry方法,順著主線呼叫鏈路找到如下方法processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	// 獲得所有的BeanDefine,也就是前面註冊的那幾個後置處理器,我們前面把後置處理器轉換成BeanDefinition註冊到了eanFactory中
	// 加上我們自己註冊的配置Bean:AppConfig
	// 前面在refresh之前,我們把AppConfig.class註冊到了BeanFactory中
	String[] candidateNames = registry.getBeanDefinitionNames();
	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		// 判斷beanDef是Full還是Lite
		// 所謂Full 就是用@Configuration註解修飾
		// 所謂Lite 就是用@Component、@ComponentScan、@Import、@ImportResource其中之一修飾
		// 下面是判斷“CONFIGURATION_CLASS_ATTRIBUTE”屬性值是Full還是Lite
		// 初次執行時CONFIGURATION_CLASS_ATTRIBUE為null,所以不走下面邏輯
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
				ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
			// 列印debug日誌而已
			...
		}
		// 預設會走這裡,檢查beanDef的註解,將他歸類為Full或Lite
		// 設定“CONFIGURATION_CLASS_ATTRIBUTE”屬性,標識它是Full還是Lite
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)){
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}
	// Return immediately if no @Configuration classes were found
	if (configCandidates.isEmpty()) {
		return;
	}
	// Sort by previously determined @Order value, if applicable
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});
	// Detect any custom bean name generation strategy supplied through the enclosing application context
	// 檢測通過封閉的應用程式上下文提供的任何自定義bean名稱生成策略
	SingletonBeanRegistry sbr = null;
	// registry實際上就是DefaultListableBeanFactory物件
	// DefaultListableBeanFactory的繼承鏈路上既有SingletonBeaRegistry,也有BeanDefinitionRegistry
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			// 從命名看來是Bean命名生成器,預設也不會走,忽略吧
			...
		}
	}
	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}
	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	// candidates是所有configBean
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		// 解析configBean,解析了config上個各類註解,掃描其他bean並註冊到BeanFactory
		// 如果是@Compent註解會直接解析並註冊到BeanFactory
		// 如果是@Import  @Bean等註解會先放入parser的ConfigurationClass,後面單獨處理
		// 其中如果是@Import的類實現了ImportBeanDefinitionRegistrars
		// 會放到configClass的ImportBeanDefinitionReistrars
		// 這裡只是Spring做了個區分,後面處理邏輯會區別對待處理而已
		parser.parse(candidates);
		parser.validate();
		//上面parse裡解析@Import、@Bean最後都放入ConfigurationClass,這裡取出來
		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		configClasses.removeAll(alreadyParsed);
		// Read the model and create bean definitions based on its content
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		// 這裡是將前面只解析但沒註冊的Bean,都註冊
		// 比如@Import、@Bean、@ImportResources
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);
		candidates.clear();
		// 在解析的過程中會發現新的Bean並註冊到BeanFactory中
		// 這裡用於做迴圈判斷,讓新註冊的Bean也會解析到
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			Set<String> alreadyParsedClasses = new HashSet<>();
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.
					checkConfigurationClassCandidate(bd, this.metadataReaderFactory)&&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());
	// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
	// 註冊一個ImportStack例項 以支援ImportAware @Configuration類,存疑
	if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
		sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
	}
	...
}
複製程式碼

這個方法我們主要關注幾點:

1、首先找到當前容器的所有BeanDefinition,預設情況下只有我們自己加入的JavaConfig和Spring自己註冊的後置處理器。

2、遍歷這些BeanDefinition,找到我們配置的Bean:@Configuration、@Component、@ComponentScan、@Import、@ImportResource等修飾的Bean,作為我們配置類,也是後面解析的入口,一般情況下只有我們自己註冊的JavaConfig。

這裡將配置類分成兩種:Full和Lite

所謂Full 就是用@Configuration註解修飾的類

所謂Lite 就是用@Component、@ComponentScan、@Import、@ImportResource其中之一修飾

Full和Lite的區別後面會有解釋,這裡只是做了個區分。

3、解析Bean

parser.parse(candidates);
複製程式碼

順著主線呼叫鏈路,執行到了doProcessConfigurationClass

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {
	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// Recursively process any member (nested) classes first
		// 首先遞迴處理(巢狀)類,先忽略吧
		processMemberClasses(configClass, sourceClass);
	}
	// Process any @PropertySource annotations
	// 處理@PropertySource註解,應用上可以把配置檔案的值直接注入到bean屬性,暫時先忽略
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		...
	}
	// Process any @ComponentScan annotations
	// 處理@ComponentScan註解
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	// 如果沒有@ComponentScan,或者@Condition條件跳過,就不再進入這個if
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		for (AnnotationAttributes componentScan : componentScans) {
			// config類使用@ComponentScan註釋 - >立即執行掃描 返回掃描到的BeanDefinitionHolder
			// 返回的就是我們加@Compent等註解的BeanDefinitionHolder
			// BeanDefinitionHolder就是BeanDefinition+nam的封裝
			// parse下面的方法暫時先不分析了,大致看了下就是基於註解轉換成BeanDefinition
			// 並註冊到BeanFactory,最後為我們返回解析到的Bean集合
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			// Check the set of scanned definitions for any further config classes and parse recursively ifneeded
			//  檢查任何進一步配置類的掃描定義集,並在需要時遞迴解析
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				// checkConfigurationClassCandidate方法前面遇到過
				// 檢查bdCand的註解,將他歸類為Full或Lite,並設定“CONFIGURATION_CLASS_ATTRIBUTE”屬性
				// 用來標識它是Full還是Lite
				// 也就是判斷掃描到的類中是否還有配置類(比如配置多資料來源),如果有遞迴解析,這個我們也忽略吧
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand,this.metadataReaderFactory)) {
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}
	// Process any @Import annotations
	// @Import註解是spring中很重要的一個註解,Springboot大量應用這個註解
	// @Import三種類,普通類,ImportSelector,ImportBeanDefinitionRegistrar
	// 存疑
	processImports(configClass, sourceClass, getImports(sourceClass), true);
	// Process any @ImportResource annotations
	// 先忽略,@ImportResource處理xml配置
	AnnotationAttributes importResource =
			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	if (importResource != null) {
		...
	}
	// Process individual @Bean methods
	// 找到@Bean修飾的方法,add到configClass
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}
	// Process default methods on interfaces
	// 先忽略,預設沒走 存疑
	processInterfaces(configClass, sourceClass);
	// Process superclass, if any
	// // 先忽略,預設沒走 存疑
	if (sourceClass.getMetadata().hasSuperClass()) {
		...
	}
	// No superclass -> processing is complete
	return null;
}
複製程式碼

這裡巨集觀上的解析邏輯,按不同註解分別解析了@ComponentScan、@Import、@Bean等註解

  • 先解析處理@PropertySource註解,就是我們常用的讀取配置檔案
  • 處理@ComponentScan註解
  • 處理@Import註解

Import裡面又分三種情況,普通Import、ImportSelector、ImportBeanDefinitionRegistrar

  • 處理@ImportResource
  • 處理@Bean修飾的方法

具體的解析邏輯還需要下鑽逐步分析...,這裡我就不扯了,也扯不明白...,到processConfigBeanDefinitions執行結束為止,大體意思應該就是掃描到的Bean轉換成BeanDefinition並註冊到BeanFactory中。

按照前面的執行規則,之後會執行ConfigurationClassPostProcessor作為BeanFactoryPostProcessor的子類的postProcessBeanFactory方法,我們主要關注如下部分

// config cglic動態代理
enhanceConfigurationClasses(beanFactory);
// 新增一個後置處理器ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
複製程式碼

前面我們的JavaConfig區分了Full和Lite,這裡就是針對Full做了處理。如果Bean是Full型別,會使用cglib動態代理重新生成JavaConfig的代理類的物件,程式碼就不分析了,也分析不明白。。。,我們直接看結果

SpringIOC原理分析

SpringIOC原理分析
在執行cglib動態代理之前,beanDefinition的beanClass屬性還是屬於AppConfig型別 在cglib動態代理之後,beanClass就變為代理類

SpringIOC原理分析

至於這裡為什麼要針對Full型別的Bean也就是@Configuration修飾的JavaConfig要使用cglib動態代理,我瞭解到的造成的影響之一是:cglib動態代理可以防止JavaConfig中的Bean重複被例項化。

我們的第二步:Bean的解析,到這裡算是結束。總結下,核心類是ConfigurationClassPostProcessor,這個後置處理器為我們解析了Bean,實際的解析邏輯我也是似懂非懂,即便如此也能大致瞭解Bean的解析過程以及Full型別的bean是使用cglib動態代理等實現。到此為止,我們定義的Bean還沒有例項化,只是被解析成BeanDefinition儲存在BeanFactory中。

Bean的例項化

前面的流程已經將Bean解析,轉換成BeanDefine並註冊到了BeanFactory

回到refresh方法,例項化過程主要依賴這兩個方法

// 註冊 BeanPostProcessor 的實現類
// 所有的BeanPostProcessor統一add到BeanFactory的beanPostProcessors屬性,準備執行
registerBeanPostProcessors(beanFactory);
// 重點,初始化所有的 singleton beans
finishBeanFactoryInitialization(beanFactory);
複製程式碼

registerBeanPostProcessors

public static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
	// 找到所有已經註冊到BeanFactory的BeanPostProcessor
	// 除了我們自己加的,還有Spring前面內建的兩個
	// AutowiredAnnotationProcessor
	// CommonAnnotationProcessor
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
	// 新增BeanPostProcessorChecker後置處理器
	// 後置處理器總數就是 前面add的後置處理器 + 1 + 註冊的BeanPostProcessor
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
	// 如果熟悉前面BeanFactoryPostProcessor的邏輯,這裡一看就懂,跟前面很相似
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	// 說一下BeanPostProcessor的註冊,前面的某些環節會加一些BeanPostProcessors
	// 有的是註冊在BeanFactory
	// 有的是直接add到AbstractBeanFactory的beanPostProcessors屬性
	// 而這裡就是將註冊在BeanFactory裡的add到AbstractBeanFactory的beanPostProcessors
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
	// Next, register the BeanPostProcessors that implement Ordered.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);
	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
	// Finally, re-register all internal BeanPostProcessors.
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);
	// 又加了個後置處理器ApplicationListenerDetector
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
複製程式碼

這個方法很簡單,前面我們分析過BeanFactoryPostProcessor的執行順序,這倆類似,只不過這裡僅僅是先註冊而已。

finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// 字母意思是如果有這個conversionService,就set值,存疑,預設沒走先忽略吧
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}
	// 忽略
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}
	// 如果有LoadTimeWeaverAware,先例項化,忽略
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}
	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);
	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();
	// Instantiate all remaining (non-lazy-init) singletons.
	// 例項化所有非延遲載入的單例,重點
	beanFactory.preInstantiateSingletons();
}
複製程式碼

後面的呼叫鏈路如下

preInstantiateSingletons->getBean->doGetBean

重點關注doGetBean

doGetBean裡首先獲得beanDefinition的class物件,取到其構造方法,然後根據構造方法例項化物件。

然後執行

...
populateBean(beanName, mbd, instanceWrapper);// Bean屬性值的注入 @Autowired
exposedObject = initializeBean(beanName, exposedObject, mbd);// 執行初始化方法
...
複製程式碼

initializeBean

就是執行初始化方法

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
		// 執行一些aware回撥
		// 如果Bean實現了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware這些介面則執行
		invokeAwareMethods(beanName, bean);
	}
	Object wrappedBean = bean;
	// 先執行beanPostProcessor的postProcessBeforeInitialization
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}
	try {// 執行初始化方法 InitializingBean 和 init-method
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}
	// 初始化方法執行完畢後,執行beanPostProcessor的postProcessAfterInitialization
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}
複製程式碼

initializeBean就決定了我們Bean的幾個初始化方法的執行順序

BeanPostProcessor -> InitializingBean -> init-method

至此bean建立完畢。這只是最常見且最簡單的一條線路。

這裡面還有很多邏輯沒有解釋,比如屬性的注入、迴圈引用等等,等有機會再補充吧

文章比較長,不定時修整、更新一下~

相關文章