search.png
关于我
menu.png
解耦的spring自动配置机制——spring.factories

spring.factories

1、概述

在一些外部依赖包中常常会看到在META-INF下,包含一个文件——spring.factories,这个文件有什么用呢?在对Eureka的研究过程中,我对这个文件进行了学习探究。

spring.factories利用了SPI机制,来实现模块的扩展配置。SPI的全名为Service Provider Interface。这个机制的原理就是面向一个通用的接口编程,实现同种功能的不同模块通过实现同一接口来方便的进行模块的替换和插拔。

2、详述

2.1 使用方式

spring.factories的语法和properties的语法是完全一致的,一般情况下是:

com.xxx.Interface = com.xxx.Impl
# 出现多个时
com.xxx.Interface = \
com.xxx.Impl1,\
com.xxx.Impl2,\
com.xxx.Impl3

key一般是接口,而value是接口的实现。

2.2 在Eureka中的使用

Eureka server包中的spring.factories如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration

其意为将EurekaServerAutoConfiguration 包括在spring的EnableAutoConfiguration自动配置中,这样在spring 启动的时候就会自动实例化这个Bean(EurekaServerAutoConfiguration)。这个Bean的作用就是对Eureka进行配置。当然Eureka的自动配置还有一个Marker机制,用来方便实现使用注解来对模块进行插拔,这个注解就是@EnableEurekaServer。在@EnableEurekaServer注解中通过@Import注入一个Marker来作为标识:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {

}

在EurekaServerMarkerConfiguration中:

@Configuration(proxyBeanMethods = false)
public class EurekaServerMarkerConfiguration {

    @Bean
    public Marker eurekaServerMarkerBean() {
        return new Marker();
    }

    class Marker {

    }

}

而当spring扫描 eureka server 包下的 META-INF/spring.factories 的时候,通过使用@ConditionalOnBean注解来使得仅当EurekaServerMarkerConfiguration.Marker这个类被注入时才会实例化EurekaServerAutoConfiguration这个环境配置Bean:

@Configuration(proxyBeanMethods = false)
@Import(EurekaServerInitializerConfiguration.class)
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
        InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
//...

}

所以因果关系是:

存在@EnableEurekaServer =>

注入了EurekaServerMarkerConfiguration.Marker =>

EurekaServerAutoConfiguration实例化时做检查:若存在EurekaServerMarkerConfiguration.Marker这个Bean =>

则实例化EurekaServerAutoConfiguration这个Bean =>

实例化所有EurekaServer相关的配置,执行初始化,之后启动Server

2.3 有什么用呢?

利用spring.factories还有类似于Eureka 自动初始化的机制,可以实现自己的模块化。打个比方,你将一个登录日志记录功能单独做成了一个模块,其中有一个简单的web应用,用来呈现登录日志的查询。那么按照传统方式你可能可以采用:

@SpringBootApplication(scanBasePackages={"com.hengyumo.loginlog.*"})

但是这样并不优雅,除了不容易读出其含义之外,一个问题是,如果将来包升级之后包名修改了,那么扫描的包也需要做修改,这样就无法实现平滑的版本升级。

而如果使用:

@EnableLoginLog

这样是不是优雅的多呢?

2.4 EnableAutoConfiguration是个注解

对于@EnableAutoConfiguration来说,SpringFactoriesLoader的用途稍微不同一些,其本意是为了提供SPI扩展的场景,而在@EnableAutoConfiguration场景中,它更多提供了一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfig.EnableAutoConfiguration作为查找的Key,获得对应的一组@Configuration类。

SpringFactoriesLoader是一个抽象类,类中定义的静态属性定义了其加载资源的路径public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories",此外还有三个静态方法:

  • loadFactories:加载指定的factoryClass并进行实例化。
  • loadFactoryNames:加载指定的factoryClass的名称集合。
  • instantiateFactory:对指定的factoryClass进行实例化。

在loadFactories方法中调用了loadFactoryNames以及instantiateFactory方法。

3、总结

通过对spring.factories的分析从另一个角度看了一下Spring的自动配置原理,同时对Eureka的自动配置原理进行了分析,具有相当的意义。在实践中可以去使用Eureka这种方式来实现自己的模块化插拔。

4、参考&引用

SpringBoot之@EnableAutoConfiguration注解

Spring Factories

最后

最近工作996很忙,写博客都是用休息的时间写的. T_T

如果帮助到你了,点个赞吧,这对博主真的很重要~

版权声明

知识共享许可协议 本文章由作者“衡于墨”创作,转载请注明出处,未经允许禁止用于商业用途

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
发布时间:2020年09月12日 11:40:22

评论区#

还没有评论哦,期待您的评论!

关闭特效