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)文章
在IntelliJ?IDEA中配置SSH服務(wù)器開發(fā)環(huán)境并實現(xiàn)固定地址遠(yuǎn)程連接的操作方法
本文主要介紹如何在IDEA中設(shè)置遠(yuǎn)程連接服務(wù)器開發(fā)環(huán)境,并結(jié)合Cpolar內(nèi)網(wǎng)穿透工具實現(xiàn)無公網(wǎng)遠(yuǎn)程連接,然后實現(xiàn)遠(yuǎn)程Linux環(huán)境進行開發(fā),本例使用的是IDEA2023.2.5版本,感興趣的朋友跟隨小編一起看看吧2024-01-01利用JDBC的PrepareStatement打印真實SQL的方法詳解
PreparedStatement是預(yù)編譯的,對于批量處理可以大大提高效率. 也叫JDBC存儲過程,下面這篇文章主要給大家介紹了關(guān)于利用JDBC的PrepareStatement打印真實SQL的方法,需要的朋友可以參考借鑒,下面來一起看看吧。2017-07-07Eclipse創(chuàng)建java程序可執(zhí)行jar包教程
這篇文章主要為大家分享了Eclipse創(chuàng)建java程序可執(zhí)行jar包教程,具有一定的實用性和參考價值,感興趣的小伙伴們可以參考一下2016-05-05springmvc+Hibernate+JPA(混合事務(wù))解讀
在Spring項目中,Spring Data JPA作為一種持久層框架,因其簡化數(shù)據(jù)庫操作而受到青睞,但在將其引入使用Hibernate的舊項目時,可能會遇到事務(wù)處理問題,解決方案包括配置兩種事務(wù)管理器:Hibernate事務(wù)管理器和JPA事務(wù)管理器2024-09-09Java語法基礎(chǔ)之選擇結(jié)構(gòu)的if語句、switch語句詳解
這篇文章主要為大詳細(xì)介紹了Java語法基礎(chǔ)之選擇結(jié)構(gòu)的if語句、switch語句,感興趣的小伙伴們可以參考一下2016-09-09IDEA導(dǎo)入外部項目報Error:java: 無效的目標(biāo)發(fā)行版: 11的解決方法
這篇文章主要介紹了IDEA導(dǎo)入外部項目報Error:java: 無效的目標(biāo)發(fā)行版: 11,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09