写在前面
spring.factories方案解决了在Spring Boot项目中,不能被默认路径扫描的情况,当然@Import注解也是一种解决方案。
spring.factories文件采用KV的形式记录了需要注册到Spring容器中的Bean的类名,SpringBoot会遍历整个项目CLASSPAHT下ClassLoader中所有JAR包下的spring.factories文件,将记录的Bean注入到Spring上下文中,与JAVA-SPI机制类似。
@ComponentScan注解的作用是扫描@SpringBootApplication注解的Application类(项目的入口类)所在的包下(当然扫描类路径是可以配置的),所有被@component注解(或拓展了@component的注解)标记的Bean,并注册到spring容器中。
使用场景
在实际的项目中,无论使用@Import还是@ComponentScan都可以将默认路径下或者以外的Bean注册到Spring上下文中,为什么还使用spring.factories文件呢?想想下面的场景:
当引用第三方依赖时,哪些类需要注册到Spring上下文中,哪些类不需要注册?显然使用@Import和@ComponentScan都不是最优解决方案,如果第三方的依赖已封装好,调用者无需关心如何注入,是不是很友好呢?这时候就产生了spring.factories方案。比如很多内置的场景启动器spring-boot-starter-XXX,都是采用这种方案。
实现原理
spring-core包里的SpringFactoriesLoader类,实现了检索 META-INF/spring.factories文件,并获取指定接口的配置的功能。在这个类中定义了两个对外的方法:
- loadFactories:根据接口类获取其实现类的实例,这个方法返回的是对象列表;
- loadFactoryNames:根据接口获取其接口类的名称,这个方法返回的是类名的列表。
上面的两个方法的关键都是从指定的ClassLoader中获取 spring.factories 文件,并解析得到类名列表,然后将这些类注册到Spring的上下文中。
spring.factories
在spring-boot-autoconfigure-2.4.2.jar中的spring.factories 中有各种KEY的使用,不同的KEY有不同的使用场景,KEY声明的是一个个的接口,VALUE是对应的实现:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
...
# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider