SpringBoot 自动配置原理以及启动流程

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】

**开源地址:https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB **

SpringBoot 自动配置原理以及启动流程

@Import(AutoConfigurationImportSelector.class)

==================================================================================================================

进入该类

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,

AnnotationMetadata annotationMetadata) {

if (!isEnabled(annotationMetadata)) {

return EMPTY_ENTRY;

}

AnnotationAttributes attributes = getAttributes(annotationMetadata);

List configurations = getCandidateConfigurations(annotationMetadata, attributes);

configurations = removeDuplicates(configurations);

Set exclusions = getExclusions(annotationMetadata, attributes);

checkExcludedClasses(configurations, exclusions);

configurations.removeAll(exclusions);

configurations = filter(configurations, autoConfigurationMetadata);

fireAutoConfigurationImportEvents(configurations, exclusions);

return new AutoConfigurationEntry(configurations, exclusions);

}

List configurations = getCandidateConfigurations(annotationMetadata, attributes);

可发现配置都通过这个方法获得

protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List 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;

}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {

return EnableAutoConfiguration.class;

}

protected ClassLoader getBeanClassLoader() {

return this.beanClassLoader;

}

//进入SpringFactoriesLoader.loadFactoryNames()方法

public static List loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {

String factoryTypeName = factoryType.getName();

return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());

}

//进入 loadSpringFactories(classLoader)

private static Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader) {

MultiValueMap<String, String> result = cache.get(classLoader);

if (result != null) {

return result;

}

try {

Enumeration urls = (classLoader != null ?

//public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;

classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :

ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

result = new LinkedMultiValueMap<>();

while (urls.hasMoreElements()) {

URL url = urls.nextElement();

UrlResource resource = new UrlResource(url);

Properties properties = PropertiesLoaderUtils.loadProperties(resource);

for (Map.Entry<?, ?> entry : properties.entrySet()) {

String factoryTypeName = ((String) entry.getKey()).trim();

for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {

result.add(factoryTypeName, factoryImplementationName.trim());

}

}

}

cache.put(classLoader, result);

return result;

}

catch (IOException ex) {

throw new IllegalArgumentException(“Unable to load factories from location [” +

FACTORIES_RESOURCE_LOCATION + “]”, ex);

}

}

//public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;

List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

通过ClassLoader加载使用了这个**@EnableAutoConfiguration**注解的类

这个方法会加载jar包中 META-INF/spring.factories 文件中配置的配置对象

SpringBoot 自动配置原理以及启动流程

SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。

spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:

SpringBoot 自动配置原理以及启动流程

接下来看看都导入了哪些组件被添加到容器中

selectImports方法

@Override

public String[] selectImports(AnnotationMetadata annotationMetadata) {

if (!isEnabled(annotationMetadata)) {

return NO_IMPORTS;

}

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader

.loadMetadata(this.beanClassLoader);

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,

annotationMetadata);

return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

}

//进入 getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata) 打个断点看看;

可以看见每个要导入的组件都以全类名的方法返回

SpringBoot 自动配置原理以及启动流程

@Conditional xxx

====================================================================================

条件注解,通过判断类路径下有没有相应配置的 jar 包来确定是否加载和自动配置这个类。

具体几个@Conditon*注解的含义

@ConditionalOnBean : 仅仅在当前上下文中存在某个对象时,才会实例化一个Bean

@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效

@ConditionalOnClass : 某个class位于类路径上,才会实例化一个Bean),该注解的参数对应的类必须存在,否则不解析该注解修饰的配置类

@ConditionalOnMissingClass : classpath中不存在该类时起效

@ConditionalOnExpression :当表达式为true的时候,才会实例化一个Bean

@ConditionalOnMissingBean :仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean,该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean,可以给该注解传入参数例如

@ConditionOnMissingBean(name = “example”),这个表示如果name为“example”的bean存在,这该注解修饰的代码块不执行

@ConditionalOnMissingClass :某个class类路径上不存在的时候,才会实例化一个Bean

@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效

@ConditionalOnProperty : 参数设置或者值一致时起效

@ConditionalOnResource : 指定的文件存在时起效

@ConditionalOnJndi : 指定的JNDI存在时起效

@ConditionalOnJava : 指定的Java版本存在时起效

@ConditionalOnWebApplication : Web应用环境下起效

@ConditionalOnNotWebApplication : 非Web应用环境下起效

结论

======================================================================

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值

  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;

  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;

  4. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;

  5. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

SpringApplication.run分析

===========================================================================================

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication

=====================================================================================

这个类主要做了以下四件事情:

==================================================================================

1、推断应用的类型是普通的项目还是Web项目

2、查找并加载所有可用初始化器 , 设置到initializers属性中

3、找出所有的应用程序监听器,设置到listeners属性中

4、推断并设置main方法的定义类,找到运行的主类

查看构造器:

public SpringApplication(ResourceLoader resourceLoader, Class… primarySources) { // …

this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值