Spring的Factories机制介绍

Posted VipSoft

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring的Factories机制介绍相关的知识,希望对你有一定的参考价值。

Java 的 SPI 机制
Java SpringBoot 加载 yml 配置文件中字典项

Spring的Factories就是Spring版本的Java Spi。 Spring Factories的最重要的功能就是:可以通过配置文件指定Spring容器加载一些特定的组件。
Spring Factories是一种类似于Java SPI的机制,它在META-INF/spring.factories文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。

Spring Factories机制提供了一种解耦容器注入的方式,帮助外部包(独立于spring-boot项目)注册Bean到spring boot项目容器中。

Spring容器管理的Bean的路径不在 Spring Boot 项目的扫描路径下

  • 在Spring Boot 项目中配置ComponentScan注解的扫描路径,添加需要被扫描的方法。
  • 通过在Spring Boot 项目中添加@EnableAutoConfiguration注解,并自定义@EnableXXXXConfiguration的注解,通过注解中的方法注入Bean。

spring.factories的是通过Properties解析得到的,所以我们在写文件中的内容都是安装下面这种方式配置的:
com.xxx.interface=com.xxx.classname

在Spring Boot的很多包中都能够找到spring.factories文件,接下来我们以spring-boot包为例进行介绍

# 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,\\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# 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


在日常工作中,我们可能需要实现一些SDK或者Spring Boot Starter给被人使用时,
我们就可以使用Factories机制。Factories机制可以让SDK或者Starter的使用只需要很少或者不需要进行配置,只需要在服务中引入我们的jar包即可。

spring.factories配置文件的工厂模式

在springboot的各个依赖包下,我们经常看到META-INF/spring.factories这个文件。spring.factories文件的内容基本上都是这样的格式:

1 # Initializers
2 org.springframework.context.ApplicationContextInitializer=3 org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,4 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

我们看到,这个文件配置了一个key:value格式的数据

1)key是:org.springframework.context.ApplicationContextInitializer

2)value是:org.springframework.context.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,org.springframework.context.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

key声明的是一个接口,value则是这个接口对应的实现类,如果有多个则以","符号分割。

简单来说,spring.factories文件包含了一些接口相对应的实现类的配置,我们通过这些配置就可以知道接口有哪些可选的实现类,并通过反射获取对应的实例对象。就像是简单工厂模式一样,也因此spring将这个文件定义为spring.factories这个名字。

代码实例

下面以ApplicationContextInitializer接口为示例,我们看看springboot是怎么使用spring.factories的。

首先会用classLoader加载类路径下的所有spring.factories的配置内容,loadSpringFactories方法将返回一个key=接口名,value=实现类集合的Map结构

 1 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) 
 2     // 先试着取缓存
 3     MultiValueMap<String, String> result = cache.get(classLoader);
 4     if (result != null) 
 5         return result;
 6     
 7 
 8     try 
 9         // 获取所有spring.factories的URL
10         Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
11         result = new LinkedMultiValueMap<>();
12         // 遍历URL
13         while (urls.hasMoreElements()) 
14             URL url = urls.nextElement();
15             UrlResource resource = new UrlResource(url);
16             // 加载每个URL中的properties配置
17             Properties properties = PropertiesLoaderUtils.loadProperties(resource);
18             // 遍历每个配置
19             for (Map.Entry<?, ?> entry : properties.entrySet()) 
20                 String factoryClassName = ((String) entry.getKey()).trim();
21                 // 将实现类的配置按照","符号分割开
22                 for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) 
23                     // 逐个添加到接口对应的集合当中
24                     result.add(factoryClassName, factoryName.trim());
25                 
26             
27         
28         // 加入缓存
29         cache.put(classLoader, result);
30         return result;
31      catch (IOException ex) 
32         // ...
33     
34 

有了以上这个Map结构,就可以轻松拿到对应接口的实现类集合了,如:

1 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) 
2     String factoryClassName = factoryClass.getName();
3     return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
4 

这里的factoryClass是接口,通过getName()方法获取全限定名,然后根据该全限定名从Map结构中get出对应的实现类全限定名的集合。

到这里我们得到了一个实现类的集合,要获取实现类具体的实例对象只需要通过反射得到实例对象即可,如:

 1 private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
 2             ClassLoader classLoader, Object[] args, Set<String> names) 
 3     List<T> instances = new ArrayList<>(names.size());
 4     // 遍历实例对象的全限定名
 5     for (String name : names) 
 6         try 
 7             // 加载该类
 8             Class<?> instanceClass = ClassUtils.forName(name, classLoader);
 9             // 断言是否为该接口的实现类
10             Assert.isAssignable(type, instanceClass);
11             // 获取构造方法
12             Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
13             // 实例化该类
14             T instance = (T) BeanUtils.instantiateClass(constructor, args);
15             // 添加到结果集当中
16             instances.add(instance);
17         
18         catch (Throwable ex) 
19             throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
20         
21     
22     return instances;
23 

 

总结

spring.factories就像是工厂一样配置了大量的接口对应的实现类,我们通过这些配置 + 反射处理就可以拿到相应的实现类。这种类似于插件式的设计方式,只要引入对应的jar包,那么对应的spring.factories就会被扫描到,对应的实现类也就会被实例化,如果不需要的时候,直接把jar包移除即可。

 

以上是关于Spring的Factories机制介绍的主要内容,如果未能解决你的问题,请参考以下文章

Spring.factories扩展机制

[SpringBoot]深入浅出剖析SpringBoot中Spring Factories机制

SpringFactoriesLoader解析

Spring Boot 扩展点应用之工厂加载机制

Spring和SpringBoot的重要回调机制

spring.factories配置文件的工厂模式