Springboot启动流程总结

前言

对Springboot的启动流程做一个学习总结


一、主要内容

1 main方法内做了什么?
2 @SpringBootApplication是何时被谁解析的

二、执行入口类的main方法

一切从这里开始,首先执行man方法,而mian方法里最主要的方法就是SpringApplication.run。跟下这个run方法

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
		System.out.println("启动成功:Sa-Token配置如下:" + SaManager.getConfig());
		System.out.println("启动成功:http://127.0.0.1:8080");
	}
}

二、创建容器

看下源码,可以看到在SpringApplication类中容器是如何创建的

public class SpringApplication {
    //首先跟到这里 这里一把run的重载方法 
	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}	
	//跟到下一个重载方法,这里创建了SpringApplication对象并调用了run方法
	//SpringApplication构造器中的参数就是mian方法所在类Application,后续容器创建后会把这个启动类注册到容器中
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
	//跟到最终的run方法
	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);
			//创建容器 稍后跟这里 这里注册了ConfigurationClassPostProcessor
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			//完成容器的装配 稍后跟这里 这里将启动类注册到了容器中		
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			//启动容器 IOC流程的入口 最后跟这里 可以看到ConfigurationClassPostProcessor是何时被调用的
			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】定义信息

ConfigurationClassPostProcessor这个类用于对Spring各种注解做解析处理,其中也包括@SpringBootApplication,这里主要跟下ConfigurationClassPostProcessor被加载的时机
需要从第二步中的createApplicationContext()方法开始跟。

public class SpringApplication {
    //这里主要是通过反射创建容器
    protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				//跟断点会执行这里 也就是创建了AnnotationConfigServletWebServerApplicationContext容器 继续跟下这个容器的无参构造器
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
}

跟AnnotationConfigServletWebServerApplicationContext的无参构造器

public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
		implements AnnotationConfigRegistry {
	public AnnotationConfigServletWebServerApplicationContext() {
	    //创建阅读器 用于读取bean定义信息并加载到容器
	    //主要跟阅读器的构造方法
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//创建扫描器
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
}

跟AnnotatedBeanDefinitionReader的构造器

public class AnnotatedBeanDefinitionReader {
    //阅读器构造器
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
	    //跟其另一个构造器
		this(registry, getOrCreateEnvironment(registry));
	}
	//另一个构造器
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		//重点在这里 这里注册了大量的beanFacotry处理器
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}
}

跟AnnotationConfigUtils.registerAnnotationConfigProcessors

public abstract class AnnotationConfigUtils {
    //跟到这个方法
    public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        //跟其重载方法
		registerAnnotationConfigProcessors(registry, null);
	}
	//registerAnnotationConfigProcessors重载方法
	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		...略

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
		//这里可以看到ConfigurationClassPostProcessor被注册到了容器中
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			//registerPostProcessor方法执行注册
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		...略 这里还注册了一些处理器
		}
		return beanDefs;
	}
}

跟这么深是因为ConfigurationClassPostProcessor类非常重要,后续启动类的注解解析全靠他。到这里ConfigurationClassPostProcessor的注册时机已经找到了


四、注册启动类定义信息到容器

启动类就是mian方法所在的类,回到SpringApplication类,看看容器创建后,启动类是如何被注册到容器中的。需要跟两个地方。第一是SpringApplication的构造器,还记得new SpringApplication时把启动类当参数传入其构造方法中吗?第二是prepareContext(…)方法将启动类添加到容器

public class SpringApplication {
    //保存资源集合
	private Set<Class<?>> primarySources;

    //步骤一 跟构造器 这里入参就是启动类
	public SpringApplication(Class<?>... primarySources) {
	    //跟另一个构造器
		this(null, primarySources);
	}
    //步骤一 跟另一个构造器
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		。。。略
		//这里可以看到将启动类信息放到了primarySources对象中
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		。。。略
	}

	//步骤二 跟prepareContext
	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		...//这里将步骤一中的启动类资源取了出来
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		//调用load方法将启动类加载到容器
		load(context, sources.toArray(new Object[0]));
		...}
    //步骤二 跟这里可以发现其把步骤一的启动类资源取了出来
	public Set<Object> getAllSources() {
		Set<Object> allSources = new LinkedHashSet<>();
		if (!CollectionUtils.isEmpty(this.primarySources)) {
			allSources.addAll(this.primarySources);
		}
		if (!CollectionUtils.isEmpty(this.sources)) {
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}
}

load方法不在继续跟了,最终是委托BeanDefinitionLoader类将启动类注册到了容器中

五、启动容器

跟第二步中的refreshContext(context);方法

public class SpringApplication {
	private void refreshContext(ConfigurableApplicationContext context) {
	    //跟refresh方法
		refresh((ApplicationContext) context);
		。。。略
	}
	//refresh方法
	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
		//继续跟
		refresh((ConfigurableApplicationContext) applicationContext);
	}
	//这里可以看到调用了容器启动方法 接下来会走IOC流程
	protected void refresh(ConfigurableApplicationContext applicationContext) {
		applicationContext.refresh();
	}
}

容器启动流程专门做了一个总结可以看这里。容器启动
接下来看看容器启动过程中ConfigurationClassPostProcessor是何时被使用的

六、刨析@SpringBootApplication

在总结ConfigurationClassPostProcessor是如何解析SpringBootApplication注解之前,先刨析下SpringBootApplication注解。
SpringBootApplication本身是一个组合注解

。。。省略4个元注解
//SpringBootConfiguration本质是一个@Configuration
@SpringBootConfiguration
//本质是一个@Import({AutoConfigurationImportSelector.class})
//完成自动装配
@EnableAutoConfiguration
//完成对当前项目的扫描 以及bean注册
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

}

通过分析SpringBootApplication 组合注解发现其本质就是【@Configuration、@Import、@ComponentScan】三类注解的组合
ConfigurationClassPostProcessor对@SpringBootApplication的解析其实就是对【@Configuration、@Import、@ComponentScan】的解析

七、ConfigurationClassPostProcessor的调用时机

ConfigurationClassPostProcessor其本身是一个BeanFactoryPostProcessor会在容器启动时调用其postProcessBeanDefinitionRegistry方法
在这里插入图片描述
继续跟applicationContext.refresh方法,容器的refresh方法统一由父类AbstractApplicationContext做了实现,所以跟AbstractApplicationContext的refresh方法

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			    。。。略
			// 跟这个方法
			invokeBeanFactoryPostProcessors(beanFactory);
			    。。。略
		}
	}
	//继续跟这里
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	    //跟委托类PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
		...}
}

跟委托类PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法

final class PostProcessorRegistrationDelegate {
    //这个方法太长了 内部内容省略了很多
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
		...//从bean工厂中拿出所有的处理器的beanName
		    String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				    //将处理器放到集合中
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			//调用处理器的方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			...}
	//接着上边的内容 跟这个方法
	private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
		//可以看到便利所有的处理器依次执行postProcessBeanDefinitionRegistry方法	
		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}
}

到这里可以发现所有BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry在容器启动时都会被调用。ConfigurationClassPostProcessor也不例外。接下来看看ConfigurationClassPostProcessor都做了什么

八、使用ConfigurationClassPostProcessor对启动类的@SpringBootApplication做解析

跟ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法,这里集合启动类来说下

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
	//入口方法
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
			...//跟这里
			processConfigBeanDefinitions(registry);
	}
	//核心方法
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//拿到所有候选bean名称 这里会拿到入口类的名称Application
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
		    //便利 这里拿到了Application的BeanDefinition 
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				。。。略
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			    //将入口类Application的BeanDefinition封装到BeanDefinitionHolde中
			    //放入configCandidates集合中
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
		...// ConfigurationClassParser是一个解析器
		// ConfigurationClassPostProcessor所有对注解的解析全部委托该类
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		...do {
		    //主要跟的方法1 这里对大量注解进行了解析处理
			parser.parse(candidates);
			parser.validate();
			  //parser.getConfigurationClasses() 这里会拿到parser.parse()的处理结果
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			。。。略
			//主要跟的方法2 这里这次不跟了  主要就是对bean定义信息的加载
			//委托给ConfigurationClassBeanDefinitionReader完成BeanDefinition注册
			this.reader.loadBeanDefinitions(configClasses);
		}
		//由循环时因为 这个过程中可能谁是由新的类被加入到容器中 需要不断的解析 
		while (!candidates.isEmpty());
		...}
}

先看parser.parse()方法 需要进入到ConfigurationClassParser 类中

class ConfigurationClassParser {
	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
			    。。。省略代码
			    //这里有很多parse的重载方法 方便阅读 只保留了一个 跟这里
				parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
			}
			。。。省略代码
		}
		//这里对@Import注解中DeferredSelector 做延迟处理  不重点看了
		this.deferredImportSelectorHandler.process();
	}
	//跟到这个方法 接着跟processConfigurationClass
	protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
		processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
	}
	//该方法主要做了条件过滤和结果保存 主要的解析需要跟doProcessConfigurationClass
	protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		//基于@Condition注解做过滤
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
        。。。省略代码
		//这里拿到了实体对象
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
		    //最终跟到这里
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		//这个循环的目的是 递归解析其各个父类
		//也就是说doProcessConfigurationClass返回结果要么是null 要么就是sourceClass的父类
		while (sourceClass != null);
		//将解析结果放到configurationClasses中
		//上边提到的parser.getConfigurationClasses()方法 最终拿到的就是这里保存的结果
		this.configurationClasses.put(configClass, configClass);
	}
	//主解析方法 这里对各种注解进行了解析
	protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
		//这里递归解析@Component注解	
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}
		//这里主要解析@PropertySources 注解
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}
		//这里主要解析@ComponentScans 注解
		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) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		//这里主要解析@Import 注解
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
		//这里主要解析@ImportResource 注解
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		//这里获取sourceClass的父类返回 与processConfigurationClass中的循环相呼应
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}
		//没有父类返回空 
		return null;
	}
}

到这里可以看到解析类主要对【@Component、@PropertySources、@ComponentScans、@Import、@ImportResource】这五类注解进行了解析。
思路回到对@SpringBootApplication组合注解的刨析。
其中@ComponentScans可以看到在这里进行了对应处理 也就是实现了 我们本项目内部的所有bean对象的加载
那么@Import又做了什么处理呢 回顾下@EnableAutoConfiguration注解中的内容【@Import(AutoConfigurationImportSelector.class)】
其内部是一个Selector,带着这个信息 继续跟processImports方法

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {
		...if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		...}
		else {
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
				    //主要看这个分支
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						//AutoConfigurationImportSelector继承了DeferredImportSelector 理论上要走这个分支 实现延迟加载
						//延迟加载最终也会走到下边的else 只是调用时机不一样 这里不展开说了 跟下边的else方法
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
						    //这里调用了selector的selectImports方法
						    //也就是说AutoConfigurationImportSelector的selectImports方法在这个时候被触发了
						    //自动装配的入口就在这里 接着跟AutoConfigurationImportSelector的selectImports方法
						    //importClassNames 是返回的所有需要自定装配的类
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); 
							//这里对自动装配的类在执行一次processImports
							//因为自动装配的类大多都是Configuration 所以再次执processImports会走到最下边的默认支持
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						...}
					else {
						...//默认会把其当做配置类 在进行一次处理
						// 自动装配的类可能会走到这里哦
						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				...}
			catch (Throwable ex) {
				...}
			finally {
			...}
		}

九、自动装配的入口

通过第八步的分析,知道了AutoConfigurationImportSelector的selectImports方法会被执行,接着跟这个方法

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	//入口方法
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		//跟这里
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		//autoConfigurationEntry.getConfigurations()这里返回所有需要自动装配的类
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

	//这个方法不在细跟了 大体总结下
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		//获取元注解信息
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//拿到所有候选的自动装配类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//去重
		configurations = removeDuplicates(configurations);
		//过滤掉需要排除的类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		//基于Condition条件过滤掉一部分类
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		//最终将结果封装到AutoConfigurationEntry中返回
		return new AutoConfigurationEntry(configurations, exclusions);
	}
}

这里将需要自动装配的类返回给第八步,最终由ConfigurationClassPostProcessor统一注册到容器中。

总结

对springboot启动的整体流程在做一次总结
1 运行main方法 里边主要执行了SpringApplication.run方法,该方法主要做了4件事
--------a 创建容器
--------b 注册ConfigurationClassPostProcessor到容器中
--------c 将带有@SpringBootApplication注解的启动类加载到了容器中
--------d 启动容器
2 容器启动过程中会调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法,该方法主要是对五个注解的解析,其中有两个比较关键的如下
--------a 解析@ComponentScan完成对本项目中bean的注册
--------b 解析@Import(AutoConfigurationImportSelector.class)完成自动装配

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值