在学完ssm后学习springboot,会惊奇地发现此前ssm的一大堆配置都消失了,而且项目竟然也可以顺利运行。

那springboot是通过了什么神奇的操作来做到这一点的呢?下面就来研究一下。

在springboot的入口处,有一个@SpringBootApplication注解,而玄机就暗藏于此。

进入源码,我们可以看到@EnableAutoConfiguration这么一个注解。

autoconfig

那这个注解是干嘛的呢?其实它就是开启了自动配置。

那springboot是根据什么东西来完成自动配置的呢?我们继续深入源码。

自动导入

在@EnableAutoConfiguration注解下,我们发现它通过EnableAutoConfigurationImportSelector导入了一些组件。

selector是选择器的意思,那么它究竟选择了什么组件导入呢?再深入源码。

自雷导入

这里似乎没有什么相关的逻辑,但是继承了一个父类,去父类瞧瞧。

父类导入

父类里有一个selectimports方法,也就是选择对应导入的组件方法,返回值是configurations转换成的数组,因此可以推测这个configuration是我们所自动导入的那些组件。得到这个configuration是靠方法中运行了另一个方法getCandidateConfigurations,翻译过来也就是获取候选的配置。

那就好解释了,springboot在运行时会通过getCandidateConfigurations方法来加载自动配置来完成原先ssm的那一大堆配置。

但是这些自动配置藏在哪呢?我们继续深挖。

leijiazai-1652186579432

可以看到这个configuration是通过Springfactoryloader运行了loadfactorynames方法加载的。

那这个方法加载了什么东西呢?

leijiazai

我们看到它指定了对应的路径,也就是类路径下meta-inf的spring.factories文件。

他获取了spring.factories后,通过下面的方法取出了其中对应的properties,那么可以推测,spring.factories应该是一个properties配置文件。

那么它取出了其中的哪个键值对呢?我们去研究一下factoryClassName。

它是通过factoryClass.getName得到的,那么这个factoryClass是什么呢?

自动2

我们通过外层进行查看,进入this.getSpringFactoriesLoaderFactoryClass()

注解

可以看到是EnableAutoConfiguration类。

那通过EnableAutoConfiguration得到的类名应该也是EnableAutoConfiguration。

我们去springboot对应的所有jar包中去寻找类路径下meta-inf的spring.factories文件找到对应的EnableAutoConfiguration键看一下。

jar

可以在springboot和springbootautoconfigure两个jar包中都找到对应的文件,但是有EnableAutoConfiguration键值对的只有一个,也就是springbootautoconfigure的jar包下的spring.factories。

配置文件

也就是说,最终springboot会把这些配置在EnableAutoConfiguration键中的值的类全部加载到容器中。

那么这些类又是什么东西呢?

随便找一个打开看看,我找的是HttpEncodingAutoConfiguration类

http

可以看到第一个注解就是@Configuration,说明这个是spring的配置类。

那就可以解释了,spring.factories文件加载的都是spring的配置类,将这些类加载到了容器中,就可以通过类中的代码实现自动配置了。

继续看下面的注解。

第二行注解是@EnableConfigurationProperties({HttpEncodingProperties.class})

看文字意思是允许配置properties,那是不是和我们平时配置的application.properties有关呢?

我们进HttpEncodingProperties.class去看看。

properties

这里有一个@ConfigurationProperties注解,给了一个prefix = "spring.http.encoding"的前缀属性,这个是不是很熟悉呢?

对了,它就是我们平时写在配置文件中的键的前缀,但是一般在这种前缀后面我们还会指定一个属性,它在哪呢?

就是class下的那些成员变量。

我们可以看到HttpEncodingProperties下有charset,force等属性,分别对应着不同的类型。

这些就是我们可以在application.properties进行配置的属性。

也就是说,我们可以通过spring.http.encoding.charset为HttpEncoding配置对应的字符集,也可以通过spring.http.encoding.force设置对应的布尔值来设定状态。

而@EnableConfigurationProperties的作用就是将配置文件的值与对应的properties类进行绑定。

那么以后如果不知道配置,只要通过源码查询对应自动配置类下的前缀以及这些成员变量,就可以轻松完成配置了,因为这些属性都被封装在了xxxxProperties的类中了。

之后还有很多Condition注解。

这些注解的意思是,只有满足了注解中列出的条件,这个自动配置类才会生效。

以下是注解的对照:

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

在以上条件都满足后,自动配置就会生效。

那还有一个问题,我们刚才只是把配置文件的属性读到了xxxproperties类中,那AutoConfiguration是怎么把xxxproperties类中的配置应用的呢?

构造柱如

可以看到在自动配置类中,有成员变量properties,通过在构造方法中添加properties参数,我们就将此前绑定好的properties类加入到了配置中。

那么简单总结一下springboot自动配置的原理:

springboot启动时,会去扫描对应jar包下配置的所有自动配置类并将其加入容器。

至于某个东西是否需要配置,我们可以在自动配置的value中查看是否存在相关配置。

如果说对应的组件已经存在,那么我们就可以使用自动配置从而不需要进行额外配置。

在加载自动配置时,会读取对应的properties类,而这些类中的属性我们可以在application.properties中根据其设定的规则进行配置。

以上就是本次springboot自动配置相关的解读。