共计 24666 个字符,预计需要花费 62 分钟才能阅读完成。
一、从 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;
}
如果本文对您有帮忙,欢送
关注
和点赞
`,您的反对是我保持创作的能源。转载请注明出处!