浅谈SpringBoot的自动配置原理

た 入场券 2023-06-29 10:53 71阅读 0赞

SpringBoot的运行原理就是基于SpringBoot的自动配置来实现。我们要想熟练的使用SpringBoot这一框架技术,就必须对其深入学习。

一:

选择SpringBoot的依赖版本:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.0.1.RELEASE</version>
  5. <relativePath/>
  6. </parent>

首先,我们先来看一下,当我们启动一个SpringBoot项目时,SpringBoot为我们自动启动了哪些自动配置类。

操作(以下三种方式任选其一)

(1)在application.properties中设置属性:

  1. debug=true

(2)通过cmd命令窗口运行xxx.jar文件

  1. java -jar xxx.jar --debug

(3)在Idea 中设置运行时参数

20200112144554536.png

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDA4MjI5_size_16_color_FFFFFF_t_70

结果

-—————————-

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDA4MjI5_size_16_color_FFFFFF_t_70 1

-—————————-

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDA4MjI5_size_16_color_FFFFFF_t_70 2


二:

接下来,我们需要学习一个注解@SpringBootApplication,这个注解是一个组合注解,他的核心功能是由@EnableAutoConfiguration注解提供。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDA4MjI5_size_16_color_FFFFFF_t_70 3

好的,然后我们来看一下@EnableAutoConfiguration 的源码:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  9. Class<?>[] exclude() default {};
  10. String[] excludeName() default {};
  11. }

兄弟们,快看!!!这其中有一个@Import注解,注意到了吗???它的作用可是非常关键的!

它的作用就是将AutoConfigurationImportSelector类导入至Spring IOC容器。于是我们就进去看看,这个类中有一个selectImports方法。具体源码如下:

  1. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  2. if (!this.isEnabled(annotationMetadata)) {
  3. return NO_IMPORTS;
  4. } else {
  5. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
  6. AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
  7. List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
  8. configurations = this.removeDuplicates(configurations);
  9. Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
  10. this.checkExcludedClasses(configurations, exclusions);
  11. configurations.removeAll(exclusions);
  12. configurations = this.filter(configurations, autoConfigurationMetadata);
  13. this.fireAutoConfigurationImportEvents(configurations, exclusions);
  14. return StringUtils.toStringArray(configurations);
  15. }
  16. }

在这个方法中,调用了AutoConfigurationMetadataLoader类的一个静态方法loadMetadata(ClassLoader classLoader)。

  1. public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
  2. return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
  3. }

这个方法用来扫描具有”META-INF/spring-autoconfigure-metadata.properties”文件的jar包,而我们的spring-boot-autoconfigure-2.0.1RELEASE.jar里就有spring.factories文件,然后我们将其打开,查看一下此文件具体有哪些自动配置。如图所示:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDA4MjI5_size_16_color_FFFFFF_t_70 4

然后我选择一个我们较为熟悉的HttpEncodingAutoConfiguration类

  1. @Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
  2. @EnableConfigurationProperties({HttpEncodingProperties.class}) //启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中
  3. @ConditionalOnWebApplication(
  4. type = Type.SERVLET
  5. )
  6. @ConditionalOnClass({CharacterEncodingFilter.class}) //判断当前项目有没有这个类CharacterEncodingFilter ; SpringMVC中进行乱码解决的过滤器;
  7. @ConditionalOnProperty(
  8. prefix = "spring.http.encoding",
  9. value = {"enabled"},
  10. matchIfMissing = true
  11. )//判断配置文件中是否存在某个配置spring.http.encoding.enabled ;如果不存在,判断也是成立的//即使我们配置文件中不配置pring.http.encoding.enabled=true ,也是默认生效的;
  12. public class HttpEncodingAutoConfiguration {
  13. private final HttpEncodingProperties properties;
  14. //只有一个有参构造器的情况下,参数的值就会从容器中拿
  15. public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
  16. this.properties = properties;
  17. }
  18. @Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
  19. @ConditionalOnMissingBean //判断容器没有这个组件?
  20. public CharacterEncodingFilter characterEncodingFilter() {
  21. CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
  22. filter.setEncoding(this.properties.getCharset().name());
  23. filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.REQUEST));
  24. filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));
  25. return filter;
  26. }
  27. @Bean
  28. public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
  29. return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
  30. }
  31. private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
  32. private final HttpEncodingProperties properties;
  33. LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {
  34. this.properties = properties;
  35. }
  36. public void customize(ConfigurableServletWebServerFactory factory) {
  37. if (this.properties.getMapping() != null) {
  38. factory.setLocaleCharsetMappings(this.properties.getMapping());
  39. }
  40. }
  41. public int getOrder() {
  42. return 0;
  43. }
  44. }
  45. }

以上源码就是根据当前不同的条件判断,决定这个配置类是否生效?一但这个配置类生效 ;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

所有在配置文件中能配置的属性都是在XxxxProperties类中封装者;配置文件能配置什么就可以参照某个功
能对应的这个属性类,比如:

  1. @ConfigurationProperties(
  2. prefix = "spring.http.encoding"
  3. ) //从配置文件中获取指定值和bean的属性进行绑定
  4. public class HttpEncodingProperties {
  5. public static final Charset DEFAULT_CHARSET;
  6. private Charset charset;
  7. private Boolean force;
  8. private Boolean forceRequest;
  9. private Boolean forceResponse;
  10. private Map<Locale, Charset> mapping;
  11. public HttpEncodingProperties() {
  12. this.charset = DEFAULT_CHARSET;
  13. }
  14. public Charset getCharset() {
  15. return this.charset;
  16. }
  17. public void setCharset(Charset charset) {
  18. this.charset = charset;
  19. }
  20. public boolean isForce() {
  21. return Boolean.TRUE.equals(this.force);
  22. }
  23. public void setForce(boolean force) {
  24. this.force = force;
  25. }
  26. public boolean isForceRequest() {
  27. return Boolean.TRUE.equals(this.forceRequest);
  28. }
  29. public void setForceRequest(boolean forceRequest) {
  30. this.forceRequest = forceRequest;
  31. }
  32. public boolean isForceResponse() {
  33. return Boolean.TRUE.equals(this.forceResponse);
  34. }
  35. public void setForceResponse(boolean forceResponse) {
  36. this.forceResponse = forceResponse;
  37. }
  38. public Map<Locale, Charset> getMapping() {
  39. return this.mapping;
  40. }
  41. public void setMapping(Map<Locale, Charset> mapping) {
  42. this.mapping = mapping;
  43. }
  44. public boolean shouldForce(HttpEncodingProperties.Type type) {
  45. Boolean force = type == HttpEncodingProperties.Type.REQUEST ? this.forceRequest : this.forceResponse;
  46. if (force == null) {
  47. force = this.force;
  48. }
  49. if (force == null) {
  50. force = type == HttpEncodingProperties.Type.REQUEST;
  51. }
  52. return force;
  53. }
  54. static {
  55. DEFAULT_CHARSET = StandardCharsets.UTF_8;
  56. }
  57. public static enum Type {
  58. REQUEST,
  59. RESPONSE;
  60. private Type() {
  61. }
  62. }
  63. }

总结:

1) SpringBoot启动会加载大量的自动配置类
2) 我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;
3) 我们再来看这个自动配置类中到底配置了哪些组件; (只要我们要用的组件有,我们就不需要再来配置了)
4) 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值;
5)
xxxxAutoConfigurartion :自动配置类;给容器中添加组件 xxxxProperties:封装配置文件中相关属性;

发表评论

表情:
评论列表 (有 0 条评论,71人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SpringBoot自动配置原理

            配置文件到底能写什么?怎么写?自动配置原理; [配置文件能配置的属性参照][Link 1] 1、自动配置原理: 1)、SpringBoot启动的时候加