Springboot自動掃描包路徑來龍去脈示例詳解
我們暫且標(biāo)注下Springboot啟動過程中較為重要的邏輯方法,源碼對應(yīng)的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定義后調(diào)用,我理解的其主要作用是執(zhí)行一些框架內(nèi)部方法也讓用戶自定義再次注入自定義的bean定義;
它的注冊是在SpringApplication.run方法調(diào)用后,具體調(diào)用鏈?zhǔn)?/p>
org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...) ->org.springframework.boot.SpringApplication#run(java.lang.String...) ->org.springframework.boot.SpringApplication#createApplicationContext //對應(yīng)上面@A標(biāo)注的地方 //后續(xù)會初始化一個org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext對象,在構(gòu)造方法里會執(zhí)行一系列的邏輯 ->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定義注入
被我們標(biāo)記了@SpringBootApplication的類在運行過程中會被包裝成一個bean定義,放入容器中;具體方法調(diào)用鏈
org.springframework.boot.SpringApplication#run(java.lang.String...) org.springframework.boot.SpringApplication#prepareContext //對應(yīng)上面代碼標(biāo)注 @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(實現(xiàn)了AnnotatedBeanDefinition接口,這很重要)
第三步:解析包掃描信息并完成剩余bean注冊
剛剛在第一步里,容器中注入了ConfigurationClassPostProcessor后置處理器,后置處理器會在核心方法refresh中執(zhí)行,也就是上面標(biāo)注@C的代碼里;
我們直接來到核心邏輯處,調(diào)用鏈:

由于第二步容器中將啟動類包裝成AnnotatedGenericBeanDefinition并注入了容器,在方法
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)會被處理執(zhí)行后續(xù)的包掃描
到此這篇關(guān)于Springboot自動掃描包路徑來龍去脈示例詳解的文章就介紹到這了,更多相關(guān)Springboot自動掃描包路徑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中的server.context-path的實現(xiàn)
本文主要介紹了SpringBoot中的server.context-path的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08
java實現(xiàn)String類型和Date類型相互轉(zhuǎn)換
很多人表示,java將string類型轉(zhuǎn)為date類型不知道應(yīng)該怎樣做,本文就來介紹一下java實現(xiàn)String類型和Date類型相互轉(zhuǎn)換,具有一定的參考價值,感興趣的可以了解一下2023-10-10
SpringCloud?Gateway?DispatcherHandler調(diào)用方法詳細(xì)介紹
我們第一個關(guān)注的類就是DispatcherHandler,這個類提供的handle()方法,封裝了我們之后所有的handlerMappings,這個DispatcherHandler有點想SpringMVC的DispatchServlet,里面也是封裝了請求和對應(yīng)的處理方法的關(guān)系2022-10-10
Java Agent入門學(xué)習(xí)之動態(tài)修改代碼
這篇文章主要給大家分享了Java Agent入門學(xué)習(xí)之動態(tài)修改代碼的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-07-07
maven中no main manifest attribute的問題解決
本文主要介紹了maven中no main manifest attribute的問題解決,這個錯誤通常意味著Spring Boot應(yīng)用在啟動時遇到了問題,下面就來具體介紹一下,感興趣的可以了解一下2024-08-08
java普通項目讀取不到resources目錄下資源文件的解決辦法
這篇文章主要給大家介紹了關(guān)于java普通項目讀取不到resources目錄下資源文件的解決辦法,Web項目中應(yīng)該經(jīng)常有這樣的需求,在maven項目的resources目錄下放一些文件,比如一些配置文件,資源文件等,需要的朋友可以參考下2023-09-09

