SpringBoot spring.factories加载时机源码分析

发布时间:2023-03-13 16:45:15 作者:iii
来源:亿速云 阅读:466

SpringBoot spring.factories加载时机源码分析

引言

在Spring Boot中,spring.factories文件扮演着非常重要的角色。它通过SPI(Service Provider Interface)机制,允许开发者在不修改Spring Boot源码的情况下,扩展和定制Spring Boot的行为。本文将深入分析spring.factories文件的加载时机及其背后的源码实现。

1. spring.factories文件的作用

spring.factories文件是Spring Boot中用于自动配置的核心文件之一。它位于META-INF目录下,通常包含一系列的键值对,用于指定Spring Boot在启动时需要加载的自动配置类、监听器、初始化器等。

例如,一个典型的spring.factories文件内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration

org.springframework.context.ApplicationListener=\
com.example.MyApplicationListener

在这个例子中,MyAutoConfiguration类将在Spring Boot启动时被自动加载,而MyApplicationListener将在应用上下文初始化时被注册为监听器。

2. spring.factories文件的加载时机

spring.factories文件的加载时机主要发生在Spring Boot应用的启动过程中。具体来说,它是在SpringApplication类的初始化阶段被加载的。

2.1 SpringApplication的初始化

SpringApplication是Spring Boot应用的入口类,负责启动Spring应用上下文。在SpringApplication的构造函数中,会调用SpringFactoriesLoader.loadFactoryNames方法来加载spring.factories文件中的配置。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

在上述代码中,getSpringFactoriesInstances方法会调用SpringFactoriesLoader.loadFactoryNames来加载spring.factories文件中的配置。

2.2 SpringFactoriesLoader的加载过程

SpringFactoriesLoader是Spring Boot中用于加载spring.factories文件的核心工具类。它通过loadFactoryNames方法从META-INF/spring.factories文件中加载指定类型的工厂类。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    String factoryTypeName = factoryType.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

loadSpringFactories方法会遍历所有META-INF/spring.factories文件,并将文件中的配置加载到一个Map中。

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
        return result;
    }

    try {
        Enumeration<URL> urls = (classLoader != null ?
                classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        result = new LinkedMultiValueMap<>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                String factoryTypeName = ((String) entry.getKey()).trim();
                for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                    result.add(factoryTypeName, factoryImplementationName.trim());
                }
            }
        }
        cache.put(classLoader, result);
        return result;
    } catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

在上述代码中,loadSpringFactories方法会从类路径中加载所有的META-INF/spring.factories文件,并将其内容解析为一个Map。这个Map的键是工厂类的全限定名,值是该工厂类的实现类的全限定名列表。

2.3 自动配置类的加载

在Spring Boot启动过程中,自动配置类的加载是通过SpringFactoriesLoader完成的。具体来说,SpringApplication会调用SpringFactoriesLoader.loadFactoryNames方法来加载spring.factories文件中定义的自动配置类。

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

在上述代码中,getCandidateConfigurations方法会调用SpringFactoriesLoader.loadFactoryNames来加载spring.factories文件中定义的自动配置类。

3. spring.factories文件的加载顺序

spring.factories文件的加载顺序是由类加载器的加载顺序决定的。通常情况下,类加载器会按照以下顺序加载类路径中的资源:

  1. Bootstrap ClassLoader:加载JVM核心类库。
  2. Extension ClassLoader:加载JVM扩展类库。
  3. Application ClassLoader:加载应用类路径中的类。

因此,spring.factories文件的加载顺序也是按照类加载器的加载顺序进行的。如果多个spring.factories文件中定义了相同的键,那么后加载的文件会覆盖先加载的文件。

4. spring.factories文件的缓存机制

为了提高性能,SpringFactoriesLoader会对加载的spring.factories文件进行缓存。具体来说,loadSpringFactories方法会将加载的spring.factories文件内容缓存到一个ConcurrentReferenceHashMap中。

private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();

在这个缓存中,键是类加载器,值是spring.factories文件的内容。这样,在下次加载相同的spring.factories文件时,可以直接从缓存中获取,而不需要重新加载。

5. spring.factories文件的扩展机制

spring.factories文件的扩展机制允许开发者在自己的项目中定义自定义的自动配置类、监听器、初始化器等。只需要在项目的META-INF/spring.factories文件中添加相应的配置即可。

例如,假设我们有一个自定义的自动配置类MyAutoConfiguration,我们可以在META-INF/spring.factories文件中添加如下配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration

这样,当Spring Boot启动时,MyAutoConfiguration类将被自动加载并应用到Spring应用上下文中。

6. 总结

spring.factories文件是Spring Boot中用于自动配置的核心文件之一。它通过SPI机制,允许开发者在不需要修改Spring Boot源码的情况下,扩展和定制Spring Boot的行为。本文详细分析了spring.factories文件的加载时机及其背后的源码实现,包括SpringApplication的初始化、SpringFactoriesLoader的加载过程、加载顺序、缓存机制以及扩展机制。

通过深入理解spring.factories文件的加载机制,开发者可以更好地利用Spring Boot的自动配置功能,定制和扩展自己的Spring Boot应用。

7. 参考资料


本文通过对spring.factories文件的加载时机及其源码的深入分析,帮助开发者更好地理解Spring Boot的自动配置机制。希望本文能为你在Spring Boot开发中提供有价值的参考和帮助。

推荐阅读:
  1. awk中的使用循环是怎么样的
  2. Linux命令学习手册-awk

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring.factories springboot

上一篇:Python二进制字节流数据的读取操作是什么

下一篇:Python如何实现arctan换算角度

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》