标签搜索

目 录CONTENT

文章目录

SpringBoot自动配置的原理

陈铭
2021-07-09 / 0 评论 / 0 点赞 / 157 阅读 / 969 字 / 正在检测是否收录...

配置关键类和注解

关于@EnableAutoConfiguration

首先,@EnableAutoConfiguration注解是@SpringBootApplication注解的一部分,顾名思义,在启动类上面标注@SpringBootApplication会自动开启自动配置。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(...)
public @interface SpringBootApplication{
    ...
}

SpringFactoriesLoader.class

开启自动配置后,在SpringBoot项目启动时,就会加载SpringFactoriesLoader.class的loadSpringFactories方法。方法中有一句代码:getResources("META-INF/spring.factories") ,也就是说,我们未配置的东西SpringBoot都会在META-INF/spring.factories中去加载。

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

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

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

AutoConfiguration结尾的类

以上两个小节说了SpringBoot为何会自动配置(@EnableAutoConfiguration)以及如何默认配置(SpringFactoriesLoader.class)。现在说说,SpringBoot如何将我们自定义的配置加载进来。这里用ServletWebServerFactoryAutoConfiguration这个类来举例。

ServletWebServerFactoryAutoConfiguration的类注解上有两个比较关键的注解@Configuration、@ConditionalOnClass()。其中@Configuration大家都比较熟悉,标注这个类就是配置类;而@ConditionalOnClass()则说明该配置类只在ServletRequest.class存在时才会加载进Spring。

因此,我们可以知道,SpringBoot内置了大量的AutoConfiguration结尾的类,这些类写好了如何配置一些属性。

@Configuration
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(...)
@EnableConfigurationProperties({ServerProperties.class})
@Import(...)
public class ServletWebServerFactoryAutoConfiguration {
    ...
}

Properties结尾的类

承接上一小节,ServletWebServerFactoryAutoConfiguration会把配置内容配置到ServletRequest中,这是由@ConditionalOnClass()控制的。ServletRequest的类注解@ConfigurationProperties表明了server前缀的配置可以配置进该类的对应属性。

那么,已经很明显了,ServletWebServerFactoryAutoConfiguration用来启动对应的配置类,最终server开头的配置信息会进入到ServerProperties的port属性。也就是我们常常配置的server.port=80。

@ConfigurationProperties(
    prefix = "server",
    ignoreUnknownFields = true
)
public class ServerProperties {
    private Integer port;
    //...
}

也就是说Properties结尾的类是SpringBoot为我们提前准备好,接受自定义配置的类。

@ConditionalOn开头的注解

上文提到了和@Configuration一起工作的注解,也就是那些@ConditionalOn开头的注解。这些注解常常作用在AutoConfiguration结尾的类上,用来限制这些配置类,这类注解还有:

@ConditionalOnBean:当容器里有指定的bean的条件下。

@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。

@ConditionalOnClass:当类路径下有指定类的条件下。

@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。

@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

小结

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

0

评论区