大致流程
-
当启动SpringBoot应用程序的时候,会先创建SpringApplication对象,在构造方法中会进行一些参数的初始化工作,比如会加载Spring.factories文件,将文件的内容放到缓存对象中,方便后续获取 -
SpringApplication对象创建完成后,开始调用run方法,启动过程中最主要有两个方法,第一个叫prepareContext(),第二个叫refreshContext()方法 -
在prepareContext()方法主要是对上下文对象ConfigurableApplicationContext的初始化操作,在整个过程中有个非常重要的方法就是load()方法,它会将当前启动类作为一个BeanDefinition注册到BeanDefinitionMap中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的启动类,来完成对应注解的解析工作 -
在refreshContext()方法会进行整个Spring容器的刷新refresh操作,会调用spring的refresh()方法,自动装配过程是在invokeBeanFactoryPostProcessor方法()中进行(也就是执行BeanFactory的后置处理器),在此方法主要是针对ConfigurationClassPostProcessor类的处理 -
在执行BeanFactory后置处理器的时候会调用ConfigurationClassPostProcessor类中的parse()方法去解析处理各种注解比如@CompomentScan、@Import等等 -
在解析@Import注解的时候比较特别,会有一个collectImports()方法,从主类开始递归解析注解,把所有包含@Import的注解都解析到BeanDefinitionMap中 -
调用AutoConfigurationImportSelector类(相当于一个处理器)中的process()方法进而触发getCandidateConfigurations()方法获取Spring.factories文件下的key为EnableAutoConfiguration的所有value,所以这就是为什么很多人的文章中都说Springboot的自动装配就是调用@EnableAutoConfiguration注解下的@Import中的AutoConfigurationImportSelector类,主要就是通过这种不断解析注解的方法去调用的
-
将所有解析到的注解的类都注册到BeanDifinitionMap中 -
至此就完成了SpringBoot的自动装配
完整流程(结合源码)
启动类
@SpringBootApplication
public class Test {
public static void main(String[] args) {
SpringApplication.run(Test.class, args);
System.out.println("启动成功");
}
}
SpringApplication的构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
run方法
public ConfigurableApplicationContext run(String... args) {
try {
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
}
prepareContext()方法
准备上下文对象,将springApplicationArguments对象和springBootBanner对象放入Spring一级缓存singletonObjects中
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
Set<Object> sources = getAllSources();
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
load()方法
将当前启动类作为一个BeanDefinition加载到BeanDefinitionMap中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的启动类,来完成对应注解的解析工作
private int load(Class<?> source) {
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
refreshContext()方法
执行完prepareContext()方法后,调用Spring的刷新容器方法refresh()
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
}
refresh()方法
这个方法相信大家非常熟悉了吧,那完成Springboot自动装配过程是在哪个阶段发生的呢?其实就是在invokeBeanFactoryPostProcessors()方法实现的
public void refresh() throws BeansException, IllegalStateException {
invokeBeanFactoryPostProcessors(beanFactory);
}
invokeBeanFactoryPostProcessors()方法
这里主要就是处理BeanFactory后置处理器,也就是直接或者间接实现BeanFactoryPostProcessor的接口的类,主要调用的是ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry()方法
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
}
}
ConfigurationClassPostProcessor类中的processConfigBeanDefinitions()方法
此方法作用就是去解析处理各种注解比如@CompomentScan、@Import等等注解
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
} while (!candidates.isEmpty());
}
ConfigurationClassParser类中的parse()方法
解析注解的入口
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
}
this.deferredImportSelectorHandler.process();
}
ConfigurationClassParser类中的doProcessConfigurationClass()方法
到达解析注解的最终方法,将解析到的Bean注册到BeanDifinitionMap中
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) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
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) {
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
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());
}
}
}
}
processImports(configClass, sourceClass, getImports(sourceClass), true);
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);
}
}
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
return null;
}
AutoConfigurationImportSelector类中的process()方法
这里的作用是读取Spring.factories文件中的内容,将所有的第三方的starter装载到BeanDefinitionMap中
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
至此,springboot的自动装配就完成了
创作不易,希望大家能够点个赞,也希望大家能帮忙指出问题,一起进步!!!谢谢大家~~
|