SpringBoot系列 - SPI机制
SpringBoot系列- SPI机制
概要
什么是SPI呢,全称是 Service Provider Interface 。简单翻译的话,就是服务提供者接口,是一种寻找服务实现的机制。这个是针对厂商或者插件的。
其实就是一个规范定义、或者说是实现的标准。
一、SPI的核心思想
SPI的核心思想是模块之间基于接口编程,不对实现类进行硬编码,增强可拔插性。它解决了模块在替换实现时无需修改代码的问题。Java SPI 提供了一种服务发现机制,用于动态寻找某接口的实现,从而在模块装配时无需显式指定具体实现。
直白一点来说就是:我定义了一个接口,但是不想固定死具体的实现类,因为那样如果要更换实现类就要改动源代码,这往往是不合适的。那么我也可以定义一个规范,在之后需要更换实现类或增加其他实现类时,遵守这个规范,我也可以动态的去发现这些实现类。
二、Spring Boot中的类SPI扩展机制
SpringBoot在启动的时候,会扫描所有jar包 resource/META-INF/spring.factories 文件,加载进去,依据类的全限定名,利用反射机制将 Bean 装载进容器中。
加载的过程是由SpringFactoriesLoader加载的。从CLASSPATH下的每个Jar包中搜寻所有META-INF/spring.factories配置文件,然后将解析properties文件,找到指定名称的配置后返回。需要注意的是,其实这里不仅仅是会去ClassPath路径下查找,会扫描所有路径下的Jar包,只不过这个文件只会在Classpath下的jar包中。
举个例子:META-INF/spring.factories中监听器的配置
监听器的实现类都是在spring.factories文件中配置好的,代码中通过getSpringFactoriesInstances方法获取,这种机制叫做SPI机制:通过本地的注册发现获取到具体的实现类,轻松可插拔。
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
这行配置表明 EventPublishingRunListener
是 SpringApplicationRunListener
接口的一个实现类。当 Spring Boot 应用启动时,它会读取 spring.factories
文件,并找到所有实现了 SpringApplicationRunListener
接口的类,并实例化它们
三、源码分析
1. 入口方法 getSpringFactoriesInstances()
根据类型获取META-INF/spring.factories文件中对应的实现类
SpringApplication构造方法:
1 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { 2 this.resourceLoader = resourceLoader; 3 Assert.notNull(primarySources, "PrimarySources must not be null"); 4 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); 5 this.webApplicationType = WebApplicationType.deduceFromClasspath(); 6 this.bootstrapRegistryInitializers = new ArrayList<>( 7 getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); 8 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); 9 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); 10 this.mainApplicationClass = deduceMainApplicationClass(); 11 }
SpringApplication#getSpringFactoriesInstances
1 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { 2 return getSpringFactoriesInstances(type, new Class<?>[]{}); 3 } 4 5 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { 6 ClassLoader classLoader = getClassLoader(); 7 // Use names and ensure unique to protect against duplicates 8 //从META-INF/spring.factories中加载对应类型的实现类 9 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); 10 // 加载上来后反射实例化 11 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); 12 //对实例列表进行排序 13 AnnotationAwareOrderComparator.sort(instances); 14 return instances; 15 }
2. SpringFactoriesLoader
SpringFactoriesLoader 是 Spring 框架中的一个工具类,用于从类路径下的 META-INF/spring.factories 文件中加载工厂类。
我们看看它源码(精简):
1 public final class SpringFactoriesLoader { 2 3 private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class); 4 5 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; 6 8 //加载spring.factories文件中的Factory名称的 9 public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { 11 } 13 14 //它只加载 spring.factories 文件中与传入的 factoryClass 对应的条目(即与给定类名匹配的键对应的实现类),并返回这些实现类的实例。 15 public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) { 17 } 18 19 //从 spring.factories 文件中加载所有的工厂类定义,并以键值对的形式返回。其中 key 是工厂接口或配置类的全限定名,value 是对应的实现类的全限定名列表。 20 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { 21 22 } 23 }
1) loadFactoryNames 方法
在该方法里,首先拿到ClassLoader,然后加载FactoryNames,加载类型(type)为ApplicationContextInitializer,类加载器(classLoader)为刚刚拿到的类加载器,返回值放入一个Set中,为的是确保没有重复的FactoryName,这是因为在之后加载的两个spring.factories配置文件中有两个重复的FactoryName。
SpringFactoriesLoader#loadFactoryNames
1 public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { 2 ClassLoader classLoaderToUse = classLoader; 3 if (classLoaderToUse == null) { 4 classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); 5 } 6 String factoryTypeName = factoryType.getName(); 7 return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); 8 }
可以看到,加载的配置文件在META-INF下,名称为spring.factories,该配置文件一共有两个,且配置文件中,每个段落第一行为Key,后边为value,读取时会通过key将所有的value拿出来。 在配置文件中我们发现,key和value都是包名加类名的字符串,因此Springboot在读取文件后,是通过反射生成的类。
SpringBoot默认情况下提供了两个spring.factories文件,分别是:
- spring-boot-2.2.2.RELEASE.jar
- spring-boot-autoconfigure-2.2.2.RELEASE.jar
spring-boot-2.2.2.RELEASE.jar - 该配置文件内容如下:
1 # PropertySource Loaders 2 org.springframework.boot.env.PropertySourceLoader=\ 3 org.springframework.boot.env.PropertiesPropertySourceLoader,\ 4 org.springframework.boot.env.YamlPropertySourceLoader 5 6 # Run Listeners 7 org.springframework.boot.SpringApplicationRunListener=\ 8 org.springframework.boot.context.event.EventPublishingRunListener 9 10 # Error Reporters 11 org.springframework.boot.SpringBootExceptionReporter=\ 12 org.springframework.boot.diagnostics.FailureAnalyzers 13 14 # Application Context Initializers 15 org.springframework.context.ApplicationContextInitializer=\ 16 org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ 17 org.springframework.boot.context.ContextIdApplicationContextInitializer,\ 18 org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ 19 org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ 20 org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer 21 22 # Application Listeners 23 org.springframework.context.ApplicationListener=\ 24 org.springframework.boot.ClearCachesApplicationListener,\ 25 org.springframework.boot.builder.ParentContextCloserApplicationListener,\ 26 org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ 27 org.springframework.boot.context.FileEncodingApplicationListener,\ 28 org.springframework.boot.context.config.AnsiOutputApplicationListener,\ 29 org.springframework.boot.context.config.ConfigFileApplicationListener,\ 30 org.springframework.boot.context.config.DelegatingApplicationListener,\ 31 org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ 32 org.springframework.boot.context.logging.LoggingApplicationListener,\ 33 org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener 34 35 # Environment Post Processors 36 org.springframework.boot.env.EnvironmentPostProcessor=\ 37 org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ 38 org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\ 39 org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\ 40 org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor 41 42 # Failure Analyzers 43 org.springframework.boot.diagnostics.FailureAnalyzer=\ 44 org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ 45 org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\ 46 org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ 47 org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ 48 org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ 49 org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\ 50 org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ 51 org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\ 52 org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ 53 org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ 54 org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\ 55 org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ 56 org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer 57 58 # FailureAnalysisReporters 59 org.springframework.boot.diagnostics.FailureAnalysisReporter=\ 60 org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
1 # Initializers 2 org.springframework.context.ApplicationContextInitializer=\ 3 org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ 4 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener 5 6 # Application Listeners 7 org.springframework.context.ApplicationListener=\ 8 org.springframework.boot.autoconfigure.BackgroundPreinitializer 9 10 # Auto Configuration Import Listeners 11 org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ 12 org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener 13 14 # Auto Configuration Import Filters 15 org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ 16 org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ 17 org.springframework.boot.autoconfigure.condition.OnClassCondition,\ 18 org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition 19 20 # Auto Configure 21 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 22 org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ 23 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ 24 org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ 25 org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ 26 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ 27 org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ 28 org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\ 29 org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ 30 org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ 31 org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ 32 org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ 33 org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ 34 org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ 35 org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\ 36 org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\ 37 org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ 38 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ 39 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\ 40 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\ 41 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ 42 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ 43 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ 44 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ 45 org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\ 46 org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\ 47 org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\ 48 org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ 49 org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ 50 org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ 51 org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\ 52 org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\ 53 org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ 54 org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ 55 org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ 56 org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ 57 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ 58 org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\ 59 org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ 60 org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ 61 org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ 62 org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ 63 org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\ 64 org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ 65 org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ 66 org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ 67 org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\ 68 org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ 69 org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\ 70 org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\ 71 org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\ 72 org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\ 73 org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\ 74 org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\ 75 org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\ 76 org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ 77 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ 78 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ 79 org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ 80 org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ 81 org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ 82 org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ 83 org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ 84 org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ 85 org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\ 86 org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\ 87 org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ 88 org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ 89 org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ 90 org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\ 91 org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ 92 org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ 93 org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ 94 org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ 95 org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ 96 org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ 97 org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ 98 org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ 99 org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\ 100 org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ 101 org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ 102 org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ 103 org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\ 104 org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\ 105 org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\ 106 org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\ 107 org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ 108 org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\ 109 org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\ 110 org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\ 111 org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ 112 org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\ 113 org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\ 114 org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ 115 org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ 116 org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ 117 org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ 118 org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\ 119 org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\ 120 org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ 121 org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\ 122 org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\ 123 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ 124 org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ 125 org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ 126 org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ 127 org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\ 128 org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\ 129 org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\ 130 org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\ 131 org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\ 132 org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\ 133 org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\ 134 org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\ 135 org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ 136 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ 137 org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\ 138 org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\ 139 org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\ 140 org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ 141 org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\ 142 org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\ 143 org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\ 144 org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\ 145 org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration 146 147 # Failure analyzers 148 org.springframework.boot.diagnostics.FailureAnalyzer=\ 149 org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ 150 org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\ 151 org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ 152 org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\ 153 org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer 154 155 # Template availability providers 156 org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ 157 org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\ 158 org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\ 159 org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\ 160 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\ 161 org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
2) loadSpringFactories 方法
SpringFactoriesLoader#loadSpringFactories
1 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { 2 //到缓存中读取 3 MultiValueMap<String, String> result = cache.get(classLoader); 4 //如果存在则直接返回 5 if (result != null) { 6 return result; 7 } 8 9 try { 10 //获取所以jar包META-INF/spring.factories对应的URL 11 Enumeration<URL> urls = (classLoader != null ? 12 classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : 13 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); 14 result = new LinkedMultiValueMap<>(); 15 //遍历数据 16 while (urls.hasMoreElements()) { 17 URL url = urls.nextElement(); 18 //获取到资源数据 19 UrlResource resource = new UrlResource(url); 20 //加载配置文件 21 Properties properties = PropertiesLoaderUtils.loadProperties(resource); 22 //遍历解析配置文件 23 for (Map.Entry<?, ?> entry : properties.entrySet()) { 24 String factoryTypeName = ((String) entry.getKey()).trim(); 25 for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { 26 //将spring.factories配置文件数据放进结果集 27 result.add(factoryTypeName, factoryImplementationName.trim()); 28 } 29 } 30 } 31 //加入缓存 32 cache.put(classLoader, result); 33 //返回结果 34 return result; 35 } 36 catch (IOException ex) { 37 throw new IllegalArgumentException("Unable to load factories from location [" + 38 FACTORIES_RESOURCE_LOCATION + "]", ex); 39 } 40 }
读取完spring.factories后,把读取到的内容(13个key)存储到枚举类中,然后遍历枚举类,将里边内容都add到一个map(result)里边去,最后把classloader以及遍历的结果都放入cache中,提高加载资源的效率。
3. createSpringFactoriesInstances
目前已经取出所有的配置,但还没有进行初始化,该方法是实例化对象的
SpringApplication#createSpringFactoriesInstances
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 for (String name : names) { 5 try { 6 Class<?> instanceClass = ClassUtils.forName(name, classLoader); 7 Assert.isAssignable(type, instanceClass); 8 //获取构造方法 9 Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); 10 //实例化对象 11 T instance = (T) BeanUtils.instantiateClass(constructor, args); 12 //加入instances实例列表 13 instances.add(instance); 14 } catch (Throwable ex) { 15 throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); 16 } 17 } 18 return instances; 19 }
四、 SPI机制的应用
Java 标准库:用于动态加载 JDBC 驱动程序、JAXP 解析器等。
Spring Boot:使用 META-INF/spring.factories 文件进行自动配置和插件管理。
第三方库:许多开源库和框架使用 SPI 来提供可插拔的功能和扩展点。
五、总结
SPI 机制具备以下特点:
1. 灵活性
服务实现可以在运行时动态加载和替换,无需修改应用程序代码。
2. 模块化
提供者和消费者的耦合度低,可以在不同的模块中实现服务,支持插件式架构。
3. 易于扩展
通过添加新的服务提供者,可以轻松扩展系统的功能,而无需修改已有的代码。
总的来说,SPI 机制提供了一种灵活的方式来实现服务的动态发现和加载,支持系统的高内聚和低耦合设计。它在 Java 标准库和许多框架(如 Spring Boot)中得到了广泛应用,能够有效地支持插件式架构和模块化设计。
参考链接:
https://www.baiyp.ren/SpringBoot%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-SPI%E6%9C%BA%E5%88%B6.html