SpringBoot 自动配置原理[通俗易懂]

SpringBoot 自动配置原理[通俗易懂]创建项目通过SpringInitialize创建SpringBoot项目而接下来要说的是关于配置文件的事情。关乎配置文件可以参考官方文档。对于配置文件来说到底在配置文件里面可以进行配置那些内容,自动配置的原理又是什么东西呢?自动配置原理在SpringBoot启动的时候加载主配置类,开启了自动配置的功能,通过@EnableAutoConfiguration注解开启自动配置的功能。@Im…

大家好,又见面了,我是你们的朋友全栈君。

创建项目

通过Spring Initialize创建SpringBoot项目
在这里插入图片描述
而接下来要说的是关于配置文件的事情。关乎配置文件可以参考官方文档。
对于配置文件来说到底在配置文件里面可以进行配置那些内容,自动配置的原理又是什么东西呢?

自动配置原理

在SpringBoot启动的时候加载主配置类,开启了自动配置的功能,通过@EnableAutoConfiguration注解开启自动配置的功能。@Import({EnableAutoConfigurationImportSelector.class})通过这个功能导入了SpringBoot自动配置的选择器。

AutoConfigurationImportSelector类

在这个类中有一个selectImports方法通过这个方法进行导入组件。在这个方法中最后的返回值是一个configurations

 public String[] selectImports(AnnotationMetadata annotationMetadata) { 
   
        if (!this.isEnabled(annotationMetadata)) { 
   
            return NO_IMPORTS;
        } else { 
   
            try { 
   
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                configurations = this.removeDuplicates(configurations);
                configurations = this.sort(configurations, autoConfigurationMetadata);
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return (String[])configurations.toArray(new String[configurations.size()]);
            } catch (IOException var6) { 
   
                throw new IllegalStateException(var6);
            }
        }
    }

作为整个方法的返回值,通过一个getCandidateConfigurations方法进行返回进入到对应的方法中可以看到

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { 
   
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

SpringFactoriesLoader.loadFactoryNames 方法

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { 
   
        String factoryClassName = factoryClass.getName();

        try { 
   
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();

            while(urls.hasMoreElements()) { 
   
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String propertyValue = properties.getProperty(factoryClassName);
                String[] var8 = StringUtils.commaDelimitedListToStringArray(propertyValue);
                int var9 = var8.length;

                for(int var10 = 0; var10 < var9; ++var10) { 
   
                    String factoryName = var8[var10];
                    result.add(factoryName.trim());
                }
            }

            return result;
        } catch (IOException var12) { 
   
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var12);
        }
    }

这个方法扫描所有jar包的类路径下的内容,META-INF/spring.factories在之前,也看过这文件里面的内容,这里提供一个新的位置
在这里插入图片描述
在这里插入图片描述
在这个里我们可以看到这里有很多的自动配置的类。这些类有见过的也没有见过的,有之前用过的,也有之前没有用过的。这个方法通过将这些内容。然后包装成了properties。在这个方法中有一个factoryClassName参数,这个参数通过下面的这个方法获取到

 protected Class<?> getSpringFactoriesLoaderFactoryClass() { 
   
        return EnableAutoConfiguration.class;
    }

从properties中获取到EnableAutoConfiguration.class类对应的值,把它们添加到容器中。而这个值就是在上面的那个图中说道的那个配置文件的值。相当于将EnableAutoConfiguration类下的所有内容都加入到容器中。所以在容器中最终会有很多的类。这里就不在详细的介绍这些类了。用到的时候在进行说明。

通过仔细观察可以知道这里的类名都是xxxAutoConfiguration。这个就表示自动配置的功能。在这里可以通过一个简单的自动配置类进行配置。

实例

HttpEncodingAutoConfiguration自动配置类

首先进入这个类会看到在这个类上面有很多的注解。这里首先一个个的看一下这些注解都是什么意思。

@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)

@Configuration
表示这个是一个配置类,这个配置类也会在容器中添加组件

@EnableConfigurationProperties(HttpEncodingProperties.class)
启用@EnableConfigurationProperties配置功能,后面跟了一个类。这个类就表示这配置内容是什么

@ConfigurationProperties(prefix = "spring.http.encoding")
从配置文件中获取到指定的值和bean与对应的属性进行绑定。这个原理在之前的时候使用的时候也提到过。
public class HttpEncodingProperties { 
   

	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

从这里可以看出基于SpringBoot的所有的配置都可以是通过一个类似于这样的配置类进行操作。

@ConditionalOnWebApplication
在Spring中底层有一个@Conditional注解这个注解表示根据不同的条件如果满足指定的条件,整个配置类里面的配置就会生效。而这个注解就是判断是否满足Web应用。如果是web应用,当前的配置生效,如果不是则不生效。

@ConditionalOnClass(CharacterEncodingFilter.class)
判断当前项目有没有对应的括号中的类,而这个过滤器就是在SpringMVC中过滤乱码的一个拦截器。

@ConditionalOnProperty(prefix = “spring.http.encoding”, value = “enabled”, matchIfMissing = true)
判断配置文件中是否存在某个配置。如果不存在,matchIfMissing 则判断成立。

上面的这些就是整体判断所有的条件都成功之后就会真正的使用到这个配置类。这个配置类生效之后又有那些内容。可以注入到容器中。一旦这个类生效,在这个类中的组件也会对应生效。但是这些组件的内容是对应的属性是从properties中获取的,这些类的每一个属性又是和配置文件绑定的。

继续往下看就会发现有新的内容

@Bean
	@ConditionalOnMissingBean(CharacterEncodingFilter.class)
	public CharacterEncodingFilter characterEncodingFilter() { 
   
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}

给容器中添加一个组件。也就是说通过@Bean的方式向容器中注入了一个Filter组件,而这个组件就是CharacterEncodingFilter类的对象,并且通过properties中获取对应的属性值。private final HttpEncodingProperties properties,它已经和SpringBoot的配置文件做了映射,也就说这个对象的值是获取了配置文件的值。

在这个类中还有一个比较值的关注的地方就是这个有参构造函数。在只有一个有参构造器的情况下。参数的值就会从容器中获取到,在之前的时候我们看到过一个@EnableConfigurationProperties(HttpEncodingProperties.class)注解,这个注解的就是将这个类HttpEncodingProperties进行了映射。

public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) { 
   
		this.properties = properties;
	}

分析到这里,就可以看到HttpEncodingProperties在这个类中的很多的属性,在配置文件中都可以进行配置。
在这里插入图片描述
在我们进行配置的时候就会看到这么多的关于HTTPencoding。在以后使用的时候可以通过查看源码获取到对应属性的用法。
在使用配置的时候,可以知道这个属性的都是通过这属性对应的properties类。

总结

  • SpringBoot启动会加载很多的自动配置类。所以我们需要的功能是不是有SpringBoot自己写好的自动配置类,
  • 然后查看对应的配置类中有那些组件,只要需要的组件在SpringBoot组件中有,就不需要在配置了。
  • 给容器中,自动添加组件的时候,会从Properties类中获取到某些属性,而这些属性就可以在配置文件中指定对应的值。

在SpringBoot中使用了很多的这样的模式,通过自动配置类向容器中添加组件,然后通过对应的Properties中的属性进行配置。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/149965.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 详解第一范式、第二范式、第三范式、BCNF范式

    详解第一范式、第二范式、第三范式、BCNF范式文章目录第一范式定义以及分析:问题研究:第二范式必备知识点函数依赖:码:非主属性:定义分析:解决办法:问题研究:第三范式:定义:分析:问题研究:BCNF范式分析问题研究小结:第一范式定义以及分析:首先是第一范式(1NF)。符合1NF的关系(你可以理解为数据表。“关系模式”和“关系”的区别,类似于面向对象程序设计中”类“与”对象“的区别。”关系“是”关系模式“的一个实例,你可以把”关系”理解…

  • CBOW全称_skip的形式

    CBOW全称_skip的形式skip-gram结构是利用中间词预测邻近词cbow模型是利用上下文词预测中间词一、CBOW1、CBOW之所以叫连续词袋模型,是因为在每个窗口内它也不考虑词序信息,因为它是直接把上下文的词向量相加了,自然就损失了词序信息。CBOW抛弃了词序信息,指的就是在每个窗口内部上下文直接相加而没有考虑词序。2、CBOW过程简单介绍如下(实际算法会用到哈夫曼编码等降维技巧,这里仅以理解为目的简介基本原理):输入为C个V维的vector。其中C为上下文窗口的大小,V为原始编码空间的规模。例如,

  • 系统日志查看journalctl命令详解

    系统日志查看journalctl命令详解简介从2012年开始,大部分linux发行版本开始从传统的systemv初始化系统移植到一个叫做systemd的全新系统。systemd用来启动系统并管理进程。systemd包含了一个叫做journalctl的辅助组件,其主要作用是管理系统的事件日志记录。journalctl可以查看所有的系统日志文件,由于日志信息量很大,journalctl还提供了各种参数帮助用户更快速的定位到日志信息。默认情况下,用户都可以访问自己的日志。对于系统主日志和其他用户的日志,仅限于有权限的用户访问,比如root用户,

  • 卷积神经网络(CNN)基础介绍

    卷积神经网络(CNN)基础介绍

  • 面渣逆袭:三万字,七十图,详解计算机网络六十二问(收藏版)

    面渣逆袭:三万字,七十图,详解计算机网络六十二问(收藏版)新年第一篇,开工大吉,虎年“豹”富!面渣逆袭系列继续,三万字+七十图详解六十二道网络面试题!强烈建议收藏!

  • ZendStudio10.6.1如何安装最新的集成svn小工具?

    ZendStudio10.6.1如何安装最新的集成svn小工具?

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号