一、從java類加載機制說起
java中的類加載器負載加載來自檔案系統、網路或者其他來源的類檔案,jvm的類加載器默認使用的是雙親委派模式,三種默認的類加載器Bootstrap ClassLoader、Extension ClassLoader和System ClassLoader(Application ClassLoader)每一個類加載器都確定了從哪些位置加載檔案,于此同時我們也可以通過繼承java.lang.classloader實作自己的類加載器,
- Bootstrap ClassLoader:負責加載JDK自帶的rt.jar包中的類檔案,是所有類加載的父類
- Extension ClassLoader:負責加載java的擴展類別庫從jre/lib/ect目錄或者java.ext.dirs系統屬性指定的目錄下加載類,是System ClassLoader的父類加載器
- System ClassLoader:負責從classpath環境變數中加載類檔案

1.1 雙親委派模型
當一個類加載器收到類加載任務時,會先交給自己的父加載器去完成,因此最終加載任務都會傳遞到最頂層的BootstrapClassLoader,只有當父加載器無法完成加載任務時,才會嘗試自己來加載,
具體:根據雙親委派模式,在加載類檔案的時候,子類加載器首先將加載請求委托給它的父加載器,父加載器會檢測自己是否已經加載過類,如果已經加載則加載程序結束,如果沒有加載的話則請求繼續向上傳遞,直至Bootstrap ClassLoader,如果請求向上委托程序中,如果始終沒有檢測到該類已經加載,則Bootstrap ClassLoader開始嘗試從其對應路勁中加載該類檔案,如果失敗則由子類加載器繼續嘗試加載,直至發起加載請求的子加載器為止,
采用雙親委派模式可以保證型別加載的安全性,不管是哪個加載器加載這個類,最終都是委托給頂層的BootstrapClassLoader來加載的,只有父類無法加載時,自己才嘗試加載,這樣就可以保證任何的類加載器最終得到的都是同樣一個Object物件
protected Class<?> loadClass(String name, boolean resolve) {
synchronized (getClassLoadingLock(name)) {
// 首先,檢查該類是否已經被加載,如果從JVM快取中找到該類,則直接回傳
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 遵循雙親委派的模型,首先會通過遞回從父加載器開始找,
// 直到父類加載器是BootstrapClassLoader為止
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
if (c == null) {
// 如果還找不到,嘗試通過findClass方法去尋找
// findClass是留給開發者自己實作的,也就是說
// 自定義類加載器時,重寫此方法即可
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
1.2 雙親委派模型缺陷
在雙親委派模型中,子類加載器可以使用父類加載器已經加載的類,而父類加載器無法使用子類加載器已經加載的,這就導致了雙親委派模型并不能解決所有的類加載器問題,
案例:Java 提供了很多服務提供者介面(Service Provider Interface,SPI),允許第三方為這些介面提供實作,常見的 SPI 有 JDBC、JNDI、JAXP 等,這些SPI的介面由核心類別庫提供,卻由第三方實作,這樣就存在一個問題:SPI 的介面是 Java 核心庫的一部分,是由BootstrapClassLoader加載的;SPI實作的Java類一般是由AppClassLoader來加載的,BootstrapClassLoader是無法找到 SPI 的實作類的,因為它只加載Java的核心庫,它也不能代理給AppClassLoader,因為它是最頂層的類加載器,也就是說,雙親委派模型并不能解決這個問題,
1.3 使用執行緒背景關系類加載器(ContextClassLoader)加載
如果不做任何的設定,Java應用的執行緒的背景關系類加載器默認就是AppClassLoader,在核心類別庫使用SPI介面時,傳遞的類加載器使用執行緒背景關系類加載器,就可以成功的加載到SPI實作的類,執行緒背景關系類加載器在很多SPI的實作中都會用到,
通常我們可以通過Thread.currentThread().getClassLoader()和Thread.currentThread().getContextClassLoader()獲取執行緒背景關系類加載器,
1.4 使用類加載器加載資源檔案,比如jar包
類加載器除了加載class外,還有一個非常重要功能,就是加載資源,它可以從jar包中讀取任何資源檔案,比如,ClassLoader.getResources(String name)方法就是用于讀取jar包中的資源檔案,
//獲取資源的方法
public Enumeration<URL> getResources(String name) throws IOException {
Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
if (parent != null) {
tmp[0] = parent.getResources(name);
} else {
tmp[0] = getBootstrapResources(name);
}
tmp[1] = findResources(name);
return new CompoundEnumeration<>(tmp);
}
它的邏輯其實跟類加載的邏輯是一樣的,首先判斷父類加載器是否為空,不為空則委托父類加載器執行資源查找任務,直到BootstrapClassLoader,最后才輪到自己查找,而不同的類加載器負責掃描不同路徑下的jar包,就如同加載class一樣,最后會掃描所有的jar包,找到符合條件的資源檔案,
// 使用執行緒背景關系類加載器加載資源
public static void main(String[] args) throws Exception{
// Array.class的完整路徑
String name = "java/sql/Array.class";
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(name);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
System.out.println(url.toString());
}
}
二、Spring中SPI機制實作
2.1 SPI機制
2.1.1 SPI思想
SPI的全名為Service Provider Interface.這個是針對廠商或者插件的,
SPI的思想:系統里抽象的各個模塊,往往有很多不同的實作方案,比如日志模塊的方案,xml決議模塊、jdbc模塊的方案等,面向的物件的設計里,我們一般推薦模塊之間基于介面編程,模塊之間不對實作類進行硬編碼,一旦代碼里涉及具體的實作類,就違反了可拔插的原則,如果需要替換一種實作,就需要修改代碼,為了實作在模塊裝配的時候能不在程式里動態指明,這就需要一種服務發現機制,
java spi就是提供這樣的一個機制:為某個介面尋找服務實作的機制,
2.1.2 SPI約定
當服務的提供者,提供了服務介面的一種實作之后,在jar包的META-INF/services/目錄里同時創建一個以服務介面命名的檔案,該檔案里就是實作該服務介面的具體實作類,而當外部程式裝配這個模塊的時候,就能通過該jar包META-INF/services/里的組態檔找到具體的實作類名,并裝載實體化,完成模塊的注入,通過這個約定,就不需要把服務放在代碼中了,通過模塊被裝配的時候就可以發現服務類了,
2.2 SPI使用案例
common-logging apache最早提供的日志的門面介面,只有介面,沒有實作,具體方案由各提供商實作, 發現日志提供商是通過掃描 META-INF/services/org.apache.commons.logging.LogFactory組態檔,通過讀取該檔案的內容找到日志提工商實作類,只要我們的日志實作里包含了這個檔案,并在檔案里制定 LogFactory工廠介面的實作類即可,
2.3 Springboot中的類SPI擴展機制
在springboot的自動裝配程序中,最侄訓加載META-INF/spring.factories檔案,而加載的程序是由SpringFactoriesLoader加載的,從CLASSPATH下的每個Jar包中搜尋所有META-INF/spring.factories組態檔,然后將決議properties檔案,找到指定名稱的配置后回傳,需要注意的是,其實這里不僅僅是會去ClassPath路徑下查找,會掃描所有路徑下的Jar包,只不過這個檔案只會在Classpath下的jar包中,
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// spring.factories檔案的格式為:key=value1,value2,value3
// 從所有的jar包中找到META-INF/spring.factories檔案
// 然后從檔案中決議出key=factoryClass類名稱的所有value值
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 取得資源檔案的URL
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
// 遍歷所有的URL
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 根據資源檔案URL決議properties檔案,得到對應的一組@Configuration類
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
// 組裝資料,并回傳
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
三、原始碼分析
先找到一個入口類getSpringFactoriesInstances
3.1 getSpringFactoriesInstances
根據型別獲取META-INF/spring.factories檔案中對應的實作類
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[]{});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//從META-INF/spring.factories中加載對應型別的類的自動配置類
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 加載上來后反射實體化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 對實體串列進行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
3.2 SpringFactoriesLoader
我們看看它的原始碼(精簡):
public abstract class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
}
}
這個類我們有利于我們繼續往下找線索的代碼是這一行:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
有了這一行代碼,我們大致就可以猜出來這個SpringFactoriesLoader類大概是干嘛的了吧?它的兩個核心方法一個是用來尋找spring.factories檔案中的Factory名稱的,一個是用來尋找類的,
3.3 loadFactoryNames
在該方法里,首先拿到ClassLoader,然后加載FactoryNames,加載型別(type)為ApplicationContextInitializer,類加載器(classLoader)為剛剛拿到的類加載器,回傳值放入一個Set中,為的是確保沒有重復的FactoryName,這是因為在之后加載的兩個spring.factories組態檔中有兩個重復的FactoryName,
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
這一步是為了使用給定的ClassLoader去給定的FACTORIES_RESOURCE_LOCATION中加載全部的工廠類
可以看到,加載的組態檔在META-INF下,名稱為spring.factories,該組態檔一共有兩個,且組態檔中,每個段落第一行為Key,后邊為value,讀取時會通過key將所有的value拿出來
在組態檔中我們發現,key和value都是包名加類名的字串,因此Springboot在讀取檔案后,是通過反射生成的類
3.3.1 spring-boot-2.2.2.RELEASE.jar

該組態檔內容如下:
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
3.3.2 spring-boot-autoconfigure-2.2.2.RELEASE.jar

該組態檔內容如下:
# 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.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
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.ElasticsearchAutoConfiguration,\
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.ReactiveRestClientAutoConfiguration,\
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.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.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
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.groovy.template.GroovyTemplateAutoConfiguration,\
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.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.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.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.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
3.4 loadSpringFactories
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//到快取中讀取
MultiValueMap<String, String> result = cache.get(classLoader);
//如果存在則直接回傳
if (result != null) {
return result;
}
try {
//獲取所以jar包META-INF/spring.factories對應的URL
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())) {
//將spring.factories組態檔資料放進結果集
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);
}
}
讀取完spring.factories后,把讀取到的內容(13個key)存盤到列舉類中,然后遍歷列舉類,將里邊內容都add到一個map(result)里邊去,最后把classloader以及遍歷的結果都放入cache中,提高加載資源的效率,
3.5 createSpringFactoriesInstances
目前已經取出所有的配置,但還沒有進行初始化,該方法是實體化物件的
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
//獲取構造方法
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
//實體化物件
T instance = (T) BeanUtils.instantiateClass(constructor, args);
//加入instances實體串列
instances.add(instance);
} catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
本文由
傳智教育博學谷教研團隊發布,如果本文對您有幫助,歡迎
關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力,轉載請注明出處!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/540436.html
標籤:Java
下一篇:java常用代碼整理
