Springboot自動掃描包路徑來龍去脈示例詳解

我們暫且標註下Springboot啟動過程中較為重要的邏輯方法,源碼對應的spring-boot-2.2.2.RELEASE版本

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			//@A
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			//@B
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			//@C
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

第一步:ConfigurationClassPostProcessor註入

org.springframework.context.annotation.ConfigurationClassPostProcessor是一個BeanDefinitionRegistryPostProcessor(父類是BeanFactoryPostProcessor),會在容器初始化好並裝載完第一階段的bean定義後調用,我理解的其主要作用是執行一些框架內部方法也讓用戶自定義再次註入自定義的bean定義;

它的註冊是在SpringApplication.run方法調用後,具體調用鏈是

org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)
->org.springframework.boot.SpringApplication#run(java.lang.String...)
->org.springframework.boot.SpringApplication#createApplicationContext 
//對應上面@A標註的地方
//後續會初始化一個org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext對象,在構造方法裡會執行一系列的邏輯
->org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry)
->org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)
->org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
->org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

//這個方法會註入5個bean定義:
1. ConfigurationClassPostProcessor.class
2. AutowiredAnnotationBeanPostProcessor.class
3. CommonAnnotationBeanPostProcessor.class
4. EventListenerMethodProcessor.class
5. DefaultEventListenerFactory.class

第二步:啟動類bean定義註入

被我們標記瞭@SpringBootApplication的類在運行過程中會被包裝成一個bean定義,放入容器中;具體方法調用鏈

org.springframework.boot.SpringApplication#run(java.lang.String...)
org.springframework.boot.SpringApplication#prepareContext //對應上面代碼標註 @B 的地方
org.springframework.boot.SpringApplication#load
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Object)
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Class<?>)
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class<?>)
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean

//裡面一段代碼 如下:
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//從這個方法裡可以看出,啟動類被包裝成瞭 AnnotatedGenericBeanDefinition(實現瞭AnnotatedBeanDefinition接口,這很重要)

第三步:解析包掃描信息並完成剩餘bean註冊

剛剛在第一步裡,容器中註入瞭ConfigurationClassPostProcessor後置處理器,後置處理器會在核心方法refresh中執行,也就是上面標註@C的代碼裡;

我們直接來到核心邏輯處,調用鏈:

ConfigurationClassPostProcessor方法被調用

由於第二步容器中將啟動類包裝成AnnotatedGenericBeanDefinition並註入瞭容器,在方法
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)會被處理執行後續的包掃描

到此這篇關於Springboot自動掃描包路徑來龍去脈示例詳解的文章就介紹到這瞭,更多相關Springboot自動掃描包路徑內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: