這篇文章主要講解了“Spring Boot配置類加載流程示例”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Spring Boot配置類加載流程示例”吧!

成都創(chuàng)新互聯(lián)公司是一家專業(yè)提供桐廬企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站制作、成都做網(wǎng)站、H5開發(fā)、小程序制作等業(yè)務(wù)。10年已為桐廬眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。
本文基于Spring Boot 1.4.1.RELEASE版本
啟動代碼如下
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleApplication.class, args);
}
}然后開始分析流程,由于Spring細(xì)節(jié)眾多,所以我們只關(guān)注重點(diǎn)就行了,不然容易迷失在其中
//ConfigurationClassPostProcessor.java
//第273行
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
//遍歷已經(jīng)注冊的所有bean
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//判斷這個bean是不是已經(jīng)被加載過的配置類
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//如果沒加載過,判斷一下是不是配置類
//這個判斷邏輯很簡單,有興趣的朋友可以自己了解一下
//因?yàn)槭枪ぞ哳悾鋵?shí)不看也不影響大局,注意這里check完之后,上邊的校驗(yàn)就是true了
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
if (configCandidates.isEmpty()) {
return;
}
//這段代碼的功能是將配置類按照Order排序,但其實(shí)沒有用,
//因?yàn)榇藭r的configCandidates列表中只有一個元素,就是SampleApplication
Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
@Override
public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
});
//省略部分代碼
//這里就是配置解析的關(guān)鍵
parser.parse(candidates);
//省略部分代碼
}接下來看ConfigurationClassParser這個類
//ConfigurationClassParser.java
//第166行
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
//遍歷所有的配置類,根據(jù)類型調(diào)用不同的parse方法
//這里分成的三種類型各代表什么,暫時不太清楚
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//省略部分代碼
}不同的parse方法會將各種參數(shù)組裝成ConfigurationClass對象,傳給processConfigurationClass()
//ConfigurationClassParser.java
//第208行
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//判斷當(dāng)前要解析的bean是否符合解析的條件
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
else {
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
}
//省略部分代碼
}
//ConditionEvaluator.java
//第73行
//AnnotatedTypeMetadata:類上的注解信息
//ConfigurationPhase:PARSE_CONFIGURATION-在解析配置時校驗(yàn);REGISTER_BEAN-在注冊bean時校驗(yàn)
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
//如果沒有配置條件,直接返回
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
//如果不指定phase,配置類使用PARSE_CONFIGURATION,其他使用REGISTER_BEAN
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
//獲取Condition并判斷條件
List<Condition> conditions = new ArrayList<Condition>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if (requiredPhase == null || requiredPhase == phase) {
if (!condition.matches(this.context, metadata)) {
return true;
}
}
}
return false;
}開始解析配置類之前,會先判斷當(dāng)前類是否符合條件以及是否已經(jīng)解析過,然后才會進(jìn)入解析流程
//ConfigurationClassParser.java
//第208行
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//省略部分代碼
//遞歸處理配置類和它的父類
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}解析的流程有點(diǎn)多,我們分段處理
1、處理嵌套(內(nèi)部)的配置類
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//先遞歸處理嵌套(內(nèi)部)的配置類
processMemberClasses(configClass, sourceClass);
//省略部分代碼
}
//ConfigurationClassParser.java
//第326行
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass memberClass : sourceClass.getMemberClasses()) {
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
//回到最開始解析的地方,遞歸處理
processConfigurationClass(memberClass.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}2、處理@PropertySource注解
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
//解析properties配置文件并放到Spring環(huán)境中
processPropertySource(propertySource);
}
else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
//省略部分代碼
}3、處理@ComponentScan注解
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
//獲取所有的@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
//根據(jù)@ComponentScan注解獲取bean
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
//判斷掃描的bean中是否有配置類,有的話繼續(xù)遞歸解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
}
//省略部分代碼
}4、處理@Import注解,@Import作用是導(dǎo)入Java配置類
Spring Boot的@EnableAutoConfiguration注解也會在這里處理,所以如果你的自動配置類被@ComponentScan注解掃描到了,只會被當(dāng)做普通的配置類,自動配置排序相關(guān)的注解(@AutoConfigureAfter等等)都是無效的
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
processImports(configClass, sourceClass, getImports(sourceClass), true);
//省略部分代碼
}
//ConfigurationClassParser.java
//第441行
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<SourceClass>();
Set<SourceClass> visited = new LinkedHashSet<SourceClass>();
collectImports(sourceClass, imports, visited);
return imports;
}
//ConfigurationClassParser.java
//第461行
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException {
//visited保存所有處理過的類,防止重復(fù)處理
if (visited.add(sourceClass)) {
//取sourceClass上的所有@Import注解,包括其他注解中的@Import注解
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
//這里不太懂為啥判斷java開頭
if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
//ConfigurationClassParser.java
//第494行
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) {
return;
}
//校驗(yàn)是否存在循環(huán)依賴
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
//如果是DeferredImportSelector接口,先暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法的最后處理(即其他配置類加載完之后)
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
//普通的ImportSelector接口直接遞歸處理
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
//ImportBeanDefinitionRegistrar接口在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執(zhí)行完畢后處理(即所有配置類加載完之后)
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
//既不是ImportSelector也不是ImportBeanDefinitionRegistrar,當(dāng)做普通的@Configuration類處理
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}5、處理@ImportResource注解,@ImportResource作用是導(dǎo)入XML配置
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
//xml配置文件跟ImportBeanDefinitionRegistrar接口一樣,也會暫存起來
//在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執(zhí)行完畢后處理(即所有配置類加載完之后)
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//省略部分代碼
}6、處理單獨(dú)的@Bean方法
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
//暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執(zhí)行完畢后處理(即所有配置類加載完之后)
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//省略部分代碼
}7、處理實(shí)現(xiàn)的接口中的default方法
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
processInterfaces(configClass, sourceClass);
//省略部分代碼
}
//ConfigurationClassParser.java
//第349行
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
//暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執(zhí)行完畢后處理(即所有配置類加載完之后)
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
//遞歸處理
processInterfaces(configClass, ifc);
}
}8、處理父類中的方法
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代碼
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
//如果存在符合條件的父類,返回它,然后繼續(xù)解析
//doProcessConfigurationClass方法被調(diào)用的地方是一個while循環(huán),只要不為null就會一直調(diào)用
return sourceClass.getSuperClass();
}
}
//省略部分代碼
}9、處理之前暫存的DeferredImportSelector接口
//ConfigurationClassParser.java
//第166行
public void parse(Set<BeanDefinitionHolder> configCandidates) {
//省略部分代碼
processDeferredImportSelectors();
}
//ConfigurationClassParser.java
//第473行
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}10、加載xml配置文件、ImportBeanDefinitionRegistrar接口實(shí)現(xiàn)類以及標(biāo)注了@Bean的方法
//ConfigurationClassPostProcessor.java
//第273行
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//省略部分代碼
this.reader.loadBeanDefinitions(configClasses);
//省略部分代碼
}
//ConfigurationClassBeanDefinitionReader.java
//第113行
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
//ConfigurationClassBeanDefinitionReader.java
//第124行
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
//省略部分代碼
if (configClass.isImported()) {
//將配置類自己也注冊成一個bean
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//將標(biāo)記了@Bean的方法加載成bean
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//加載XML配置文件
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//加載ImportBeanDefinitionRegistrar接口的實(shí)現(xiàn)
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}感謝各位的閱讀,以上就是“Spring Boot配置類加載流程示例”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Spring Boot配置類加載流程示例這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
當(dāng)前文章:SpringBoot配置類加載流程示例
URL分享:http://chinadenli.net/article8/pgjgop.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計、網(wǎng)站設(shè)計、微信公眾號、網(wǎng)站收錄、品牌網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)