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)


相关推荐

  • java—二分查找法[通俗易懂]

    java—二分查找法[通俗易懂]/** * 二分查找法 * 注: 数组元素必须有顺序 * */public class sort4 { public static void main(String[] args) { int [] arr ={1,2,3,4,5,6,7,8}; int a = binarySerarch(arr,7); // 从这些数中查找7返回这个数字的索引 System….

  • VScode快捷键设置和代码简写

    VScode快捷键设置和代码简写1常用快捷键 单行注释 ctrl+/ 多行注释 alt+shift+a 复制上一行代码到下一行 alt+shift+↓ 移动代码到上一行或下一行 alt+↑,alt+↓ 返回到上次编辑位置 alt…

  • 中缀表达式转换为后缀表达式(栈的使用)

    中缀表达式如1*2+(2-1), 其运算符一般出现在操作数之间, 因此称为中缀表达式,也就是大家编程中写的表达式。编译系统不考虑表达式的优先级别, 只是对表达式从左到右进行扫描, 当遇到运算符时, 就把其前面的两个操作数取出, 进行操作。为达到上述目的, 就要将中缀表达式进行改写,变为后缀表达式 如上面的表达式1*2+(2-1), 就变为12*21-+;后缀表达式中不含有括号, 且

  • python表白代码-表白python代码

    python表白代码-表白python代码广告关闭2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品。未来,我们一起乘风破浪,创造无限可能。七夕快到了,表白素材赶紧先准备好。。。0、委婉的表白python代码:importstringl=string.ascii_letterss=s.append(l)s.append(l)s.append(l)s.append(l)s.append(l)s.appe…

  • c++实现登录注册功能(用Javaweb制作登录注册页面)

    这两天c#大作业要求做一个简单的通讯录系统,我就先做了登录和注册的功能,在网上看了一些代码,自己再做,终于做出来了。做的不是很美观,但是可以简单实现。首先用sqlserver建表。我建了一个名为user_info的表,添加username和passdword两个字段。创建登录页面,改了一些控件的名称,效果如下图:登录界面代码如下:privatevoidbtn_Login…

  • gpsgate 配置过程

    gpsgate 配置过程gpsgate是一个虚拟串口的软件。通过gpsgate虚拟出来的串口可以同时连接N个应用程序。举个例子来说,QIGI智能手机的gps通讯端口是com3,波特率手是9600。我们通过gpsgate虚拟出

发表回复

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

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