Spring Boot自动装配及启动流程源码分析

2022年10月26日10:15:55

一、Spring Boot自动装配源码分析

首先主启动类上写上@SpringBootApplication。

@SpringBootApplicationpublicclassSpringSourceApplication{publicstaticvoidmain(String[] args){
		SpringApplication.run(SpringSourceApplication.class, args);}}

这个注解做了什么?

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters={@Filter(type= FilterType.CUSTOM, classes= TypeExcludeFilter.class),@Filter(type= FilterType.CUSTOM, classes= AutoConfigurationExcludeFilter.class)})public @interfaceSpringBootApplication{...}

这时,我们发现@EnableAutoConfiguration这个注解,看名字我们大胆猜测就是开启自动配置。

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interfaceEnableAutoConfiguration{...}

这个注解上又有两个核心的注解:@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)。

下面我们分别看看它们做了什么?
@AutoConfigurationPackage注解导入了AutoConfigurationPackages.Registrar.class。

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public @interfaceAutoConfigurationPackage{

	String[]basePackages()default{};

	Class<?>[]basePackageClasses()default{};}

Registrar 实现了ImportBeanDefinitionRegistrar接口,则在解析配置类时,会调用registerBeanDefinitions方法。

staticclassRegistrarimplementsImportBeanDefinitionRegistrar, DeterminableImports{@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry){//注册beandefinitionregister(registry,newPackageImports(metadata).getPackageNames().toArray(newString[0]));}@Overridepublic Set<Object>determineImports(AnnotationMetadata metadata){return Collections.singleton(newPackageImports(metadata));}}

debug跟踪下,

PackageImports(AnnotationMetadata metadata){//获取@AutoConfigurationPackage的属性"basePackageClasses" 和"basePackages"
		AnnotationAttributes attributes= AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(),false));
		List<String> packageNames=newArrayList<>(Arrays.asList(attributes.getStringArray("basePackages")));for(Class<?> basePackageClass: attributes.getClassArray("basePackageClasses")){
			packageNames.add(basePackageClass.getPackage().getName());}//获取的包名为空if(packageNames.isEmpty()){//获得主启动类的包名
		  packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));}//赋值给packageNames属性this.packageNames= Collections.unmodifiableList(packageNames);}

注册BeanDefinition,beanName是org.springframework.boot.autoconfigure.AutoConfigurationPackages,设置它的basePackages是我们的包名。

@AutoConfigurationPackage注解的主要作用就是将主程序类所在包及所有子包下的组件到扫描到spring容器中。

重点是@EnableAutoConfiguration注解上import了另一个AutoConfigurationImportSelector。

AutoConfigurationImportSelector实现DeferredImportSelector接口。
在解析配置@Import注解时,如果实现了DeferredImportSelector,则会调用 getImportGroup()方法,返回Class,再调用它的process方法。
我们这里getImportGroup()方法
调用链路:


refreshinvokeBeanFactoryPostProcessors(beanFactory);
     invokeBeanDefinitionRegistryPostProcessors
     	ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(registry)
        	ConfigurationClassPostProcessor.processConfigBeanDefinitions
          		parser.parse(candidates)
          			doProcessConfigurationClassprocessImports(configClass, sourceClass,getImports(sourceClass),true)this.deferredImportSelectorHandler.handle(configClass,(DeferredImportSelector) selector);this.deferredImportSelectors.add(holder);this.deferredImportSelectorHandler.process()register(DeferredImportSelectorHolder deferredImport)
		          	   		deferredImport.getImportSelector().getImportGroup();//这里就调用了AutoConfigurationImportSelector的 getImportGroup()方法,返回AutoConfigurationGroup.class
		          	   		handler.processGroupImports();
		          	   			grouping.getImports()//这个里面的两个核心方法执行完,就获得了走动配置类的信息,后面再循环,继续递归处理调用processImportsthis.group.process(deferredImport.getConfigurationClass().getMetadata(),deferredImport.getImportSelector())//调用AutoConfigurationImportSelector的process方法this.group.selectImports();//加载BeanDefinitionsthis.reader.loadBeanDefinitions(configClasses);

getImportGroup方法返回AutoConfigurationGroup.class

@Overridepublic Class<?extendsGroup>getImportGroup(){return AutoConfigurationGroup.class;}

那么程序会调用AutoConfigurationGroup.process方法:

@Overridepublicvoidprocess(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector){
	Assert.state(deferredImportSelectorinstanceofAutoConfigurationImportSelector,()-> String.format("Only %s implementations are supported, got %s",
					AutoConfigurationImportSelector.class.getSimpleName(),
					deferredImportSelector.getClass().getName()));//获取自动配置entry
	AutoConfigurationEntry autoConfigurationEntry=((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);this.autoConfigurationEntries.add(autoConfigurationEntry);for(String importClassName: autoConfigurationEntry.getConfigurations()){this.entries.putIfAbsent(importClassName, annotationMetadata);}}

getAutoConfigurationEntry方法

protected AutoConfigurationEntrygetAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata){if(!isEnabled(annotationMetadata)){return EMPTY_ENTRY;}
	AnnotationAttributes attributes=getAttributes(annotationMetadata);//获取候选的配置类
	List<String> configurations=getCandidateConfigurations(annotationMetadata, attributes);//去重
	configurations=removeDuplicates(configurations);//获取需要排除,@EnableAutoConfiguration配置的exclude和excludeName;和spring.autoconfigure.exclude属性配置的
	Set<String> exclusions=getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);//排除
	configurations.removeAll(exclusions);//获取自动配置类,key为org.springframework.boot.autoconfigure.AutoConfigurationImportFilter的Condition,然后调用match方法,留下按有效的
	configurations=filter(configurations, autoConfigurationMetadata);fireAutoConfigurationImportEvents(configurations, exclusions);returnnewAutoConfigurationEntry(configurations, exclusions);}

获取自动配置类方法getCandidateConfigurations

protected List<String>getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes){
    
	List<String> configurations= SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
	Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories. If you "+"are using a custom packaging, make sure that file is correct.");return configurations;}

获取要获取配置文件的key,这里是org.springframework.boot.autoconfigure.EnableAutoConfiguration

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
	return EnableAutoConfiguration.class;
}
publicstatic List<String>loadFactoryNames(Class<?> factoryType,@Nullable ClassLoader classLoader){// factoryTypeName是org.springframework.boot.autoconfigure.EnableAutoConfiguration
	String factoryTypeName= factoryType.getName();returnloadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}

loadSpringFactories方法,加载配置文件内容

privatestatic Map<String, List<String>>loadSpringFactories(@Nullable ClassLoader classLoader){//先从缓存中取
	MultiValueMap<String, String> result= cache.get(classLoader);if(result!= null){return result;}try{//FACTORIES_RESOURCE_LOCATION是 META-INF/spring.factories,加载所有jar包里的这个文件
		Enumeration<URL> urls=(classLoader!= null?
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION):
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result=newLinkedMultiValueMap<>();while(urls.hasMoreElements()){
			URL url= urls.nextElement();
			UrlResource resource=newUrlResource(url);
			Properties properties= PropertiesLoaderUtils.loadProperties(resource);for(Map.Entry<?,?> entry: properties.entrySet()){
				String factoryTypeName=((String) entry.getKey()).trim();//逗号分隔valuefor(String factoryImplementationName: StringUtils.commaDelimitedListToStringArray((String) entry.getValue())){
					result.add(factoryTypeName, factoryImplementationName.trim());}}}//放入缓存
		cache.put(classLoader, result);return result;}catch(IOException ex){thrownewIllegalArgumentException("Unable to load factories from location ["+
				FACTORIES_RESOURCE_LOCATION+"]", ex);}}

最后回调selectImports方法

public Iterable<Entry>selectImports(){if(this.autoConfigurationEntries.isEmpty()){return Collections.emptyList();}
		Set<String> allExclusions=this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
		Set<String> processedConfigurations=this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));
		processedConfigurations.removeAll(allExclusions);returnsortAutoConfigurations(processedConfigurations,getAutoConfigurationMetadata()).stream().map((importClassName)->newEntry(this.entries.get(importClassName), importClassName)).collect(Collectors.toList());}

总结:

其实就是import了AutoConfigurationImportSelector,而AutoConfigurationImportSelector实现DeferredImportSelector接口。
加载所有jar包里的META-INF/spring.factories文件。

二、Spring Boot启动流程源码分析

带着两个疑问看下Spring Boot启动流程源码

1、什么时候启动的内置tomcat?
2、什么时候注册的DispatcherServlet?

在META-INF/spring.factories的自动配置类里有两个与其相关的自动配置类DispatcherServletAutoConfiguration和ServletWebServerFactoryAutoConfiguration。

首先看下这个ServletWebServerFactoryAutoConfiguration 类。

@Configuration(proxyBeanMethods=false)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@ConditionalOnClass(ServletRequest.class)@ConditionalOnWebApplication(type= Type.SERVLET)@EnableConfigurationProperties(ServerProperties.class)@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class})publicclassServletWebServerFactoryAutoConfiguration{@Beanpublic ServletWebServerFactoryCustomizerservletWebServerFactoryCustomizer(ServerProperties serverProperties){returnnewServletWebServerFactoryCustomizer(serverProperties);}@Bean@ConditionalOnClass(name="org.apache.catalina.startup.Tomcat")public TomcatServletWebServerFactoryCustomizertomcatServletWebServerFactoryCustomizer(
			ServerProperties serverProperties){returnnewTomcatServletWebServerFactoryCustomizer(serverProperties);}...}

首先导入了ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar类,该类实现ImportBeanDefinitionRegistrar接口,所以ConfigurationClassPostProcessor解析配置类的时候,自动调用该接口的registerBeanDefinitions方法。

@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadata importingClassMetadata,
		BeanDefinitionRegistry registry){if(this.beanFactory== null){return;}registerSyntheticBeanIfMissing(registry,"webServerFactoryCustomizerBeanPostProcessor",
			WebServerFactoryCustomizerBeanPostProcessor.class);registerSyntheticBeanIfMissing(registry,"errorPageRegistrarBeanPostProcessor",
			ErrorPageRegistrarBeanPostProcessor.class);}

这里的BeanPostProcessorsRegistrar在该方法中注册了两个bean的定义信息:一个是ErrorPageRegistrarBeanPostProcessor,另一个是注册的bean定义信息是WebServerFactoryCustomizerBeanPostProcessor,主要是WebServerFactoryCustomizerBeanPostProcessor。

publicclassWebServerFactoryCustomizerBeanPostProcessorimplementsBeanPostProcessor, BeanFactoryAware{@Overridepublic ObjectpostProcessBeforeInitialization(Object bean, String beanName)throws BeansException{//在创建bean的初始化前执行,只拦截WebServerFactory的beanif(beaninstanceofWebServerFactory){postProcessBeforeInitialization((WebServerFactory) bean);}return bean;}privatevoidpostProcessBeforeInitialization(WebServerFactory webServerFactory){//获得WebServerFactoryCustomizer,执行customizer的customize方法
		LambdaSafe.callbacks(WebServerFactoryCustomizer.class,getCustomizers(), webServerFactory).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class).invoke((customizer)-> customizer.customize(webServerFactory));}}

作用是对WebServerFactory工厂做一些定制化的工作(配置)。

再回来看ServletWebServerFactoryAutoConfiguration,还导入了其他三个组件:
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class
ServletWebServerFactoryConfiguration.EmbeddedJetty.class
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class

默认情况,只有EmbeddedTomcat会生效。导入了一个TomcatServletWebServerFactory类型的组件。后面tomcat的创建就靠它。

@Beanpublic TomcatServletWebServerFactorytomcatServletWebServerFactory(
		ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
		ObjectProvider<TomcatContextCustomizer> contextCustomizers,
		ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers){
	TomcatServletWebServerFactory factory=newTomcatServletWebServerFactory();
	factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
	factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
	factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));return factory;}

现在我们再看看DispatcherServletAutoConfiguration配置类

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@Configuration(proxyBeanMethods=false)@ConditionalOnWebApplication(type
  • 作者:小相公爱玩
  • 原文链接:https://blog.csdn.net/u010342147/article/details/123475286
    更新时间:2022年10月26日10:15:55 ,共 12654 字。