一、从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 Loadersorg.springframework.boot.env.PropertySourceLoader=\org.springframework.boot.env.PropertiesPropertySourceLoader,\org.springframework.boot.env.YamlPropertySourceLoader# Run Listenersorg.springframework.boot.SpringApplicationRunListener=\org.springframework.boot.context.event.EventPublishingRunListener# Error Reportersorg.springframework.boot.SpringBootExceptionReporter=\org.springframework.boot.diagnostics.FailureAnalyzers# Application Context Initializersorg.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 Listenersorg.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 Processorsorg.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 Analyzersorg.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# FailureAnalysisReportersorg.springframework.boot.diagnostics.FailureAnalysisReporter=\org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
3.3.2 spring-boot-autoconfigure-2.2.2.RELEASE.jar

该配置文件内容如下:

# Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.autoconfigure.BackgroundPreinitializer# Auto Configuration Import Listenersorg.springframework.boot.autoconfigure.AutoConfigurationImportListener=\org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener# Auto Configuration Import Filtersorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\org.springframework.boot.autoconfigure.condition.OnBeanCondition,\org.springframework.boot.autoconfigure.condition.OnClassCondition,\org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition# Auto Configureorg.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 analyzersorg.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 providersorg.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;}

如果本文对您有帮忙,欢送关注点赞`,您的反对是我保持创作的能源。

转载请注明出处!