前言
对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)完成自动装配