最新要闻
- 天天有喜大结局是什么?天天有喜演员表
- 蜜糖三部曲是哪部电视剧?蜜糖三部曲有什么关系?
- 华约自主招生是什么意思?华约自主招生考试笔试经验
- 如何用环保袋制作衣服?用环保袋制作衣服的方法有哪些?
- 女医明妃传原型是谁?女医明妃传演员表
- 冒险岛怎么删除角色?冒险岛怎么提升面板?
- 高考穿什么衣服寓意好?高考穿什么衣服吉利?
- 红海行动是根据哪个真实事件改编的?红海行动真实事件原型
- 女娲传说之灵珠大结局是什么?女娲传说之灵珠演员表介绍
- 福州一中地址在哪里?福州一中录取分数线2022
- 还转投N卡阵营吗?国内AMD RX7900 XT货源开始变多 7599元起
- 最新资讯:本田真爱粉狂喜 全新思域两厢版上市:手动挡卖到16万
- 三只松鼠年货坚果礼盒大促:109立减60元 49包邮到手
- 高分天气应用Dark Sky即将关闭:苹果呼吁用户使用自带天气
- 天天新资讯:谷爱凌再创一新世界纪录:反脚1260板尾抓板女子世界第一
- 影响力无敌!梅西夺冠帖点赞量成Instagram史上第一:球衣被抢光
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
环球新消息丨【源码透视】SpringBoot的SPI机制
一、从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 getResources(String name) throws IOException { Enumeration[] tmp = (Enumeration[]) 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 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 loadFactoryNames(Class> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); // 取得资源文件的URL Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List result = new ArrayList(); // 遍历所有的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 Collection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class>[]{});}private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates //从META-INF/spring.factories中加载对应类型的类的自动配置类 Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 加载上来后反射实例化 List 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 List loadFactories(Class factoryClass, ClassLoader classLoader) { } public static List 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 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> loadSpringFactories(@Nullable ClassLoader classLoader) { //到缓存中读取 MultiValueMap result = cache.get(classLoader); //如果存在则直接返回 if (result != null) { return result; } try { //获取所以jar包META-INF/spring.factories对应的URL Enumeration 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 List createSpringFactoriesInstances(Class type, Class>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List 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;}
本文由
传智教育博学谷
教研团队发布。如果本文对您有帮助,欢迎
关注
和点赞
;如果您有任何建议也可留言评论
或私信
,您的支持是我坚持创作的动力。转载请注明出处!
-
快播:火山引擎 DataTester 为企业降本增效:1 个人也能成为一支 A/B 实验团队
更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群今年天猫电商、...
来源: 环球新消息丨【源码透视】SpringBoot的SPI机制
快播:火山引擎 DataTester 为企业降本增效:1 个人也能成为一支 A/B 实验团队
Netty-介绍-1
天天有喜大结局是什么?天天有喜演员表
Mybatis批量插入3种方法
蜜糖三部曲是哪部电视剧?蜜糖三部曲有什么关系?
华约自主招生是什么意思?华约自主招生考试笔试经验
如何用环保袋制作衣服?用环保袋制作衣服的方法有哪些?
全球资讯:青龙面板之淘宝
当前热点-彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-JWT和中间件(Middleware)的使用EP07
全球资讯:数智赋能:透过低代码看企业如何实现数智转型
速读:基于 Dubbo Admin 实现流量灰度
女医明妃传原型是谁?女医明妃传演员表
冒险岛怎么删除角色?冒险岛怎么提升面板?
高考穿什么衣服寓意好?高考穿什么衣服吉利?
红海行动是根据哪个真实事件改编的?红海行动真实事件原型
女娲传说之灵珠大结局是什么?女娲传说之灵珠演员表介绍
福州一中地址在哪里?福州一中录取分数线2022
Qt做大型软件开发技术选型Part2:Qt调用C#编写的COM组件
世界视讯!Cpp Primer:Sec 4, 5, 6
【当前独家】项目管理工具飞项傍身,居家办公效率“快人一步”
要闻:redis—安装以及可视化
还转投N卡阵营吗?国内AMD RX7900 XT货源开始变多 7599元起
最新资讯:本田真爱粉狂喜 全新思域两厢版上市:手动挡卖到16万
三只松鼠年货坚果礼盒大促:109立减60元 49包邮到手
高分天气应用Dark Sky即将关闭:苹果呼吁用户使用自带天气
天天新资讯:谷爱凌再创一新世界纪录:反脚1260板尾抓板女子世界第一
管理经验
环球速看:程序员面试找替身 “作弊” 入职,结果大快人心。。。
影响力无敌!梅西夺冠帖点赞量成Instagram史上第一:球衣被抢光
最纯净的国产手机系统!博主实测努比亚Z50系统广告默认关闭:世界清净了
环球观焦点:当AI作画入侵鬼畜区
全球时讯:不适合中国观众 只有《流浪地球2》?出品方:《阿凡达2》没理由不引进
质感绝了!一加11海外官宣:2月7日登场
【环球新要闻】SSD白菜价先别下单:有猫腻
世界动态:使用brew安装历史版本的几种方式
当前快讯:第一百一十六篇: JavaScript理解对象
世界微资讯!Python参数解析器configparser
民间大神用虚幻5自制《原神》 :这视觉效果爱了
【环球报资讯】曾经缔造玛雅文明!为什么玉米的产量世界第一?
深扒《阿凡达2》背后的故事:才是真的“细思恐极”!
【全球快播报】蔚来CEO李斌回应数据泄露问题 绝不会与不法行为妥协
全球热推荐:我去大疆新总部逛了逛:评测了有史以来最大的“产品”
焦点速递!Python unittest+ddt+openpyxl接口自动化
今日热讯:MAUI新生4.4-笔刷Brush
每日焦点!梅西晒怀抱大力神杯入睡照!淘宝同款奖杯被抢光
速讯:python + selenium实现gitlab全文搜索
热资讯!Codeforces 1763 F Edge Queries 题解
天天视讯!如何使用Yum History查找已安装或已删除的软件包信息
天天新消息丨混合场景
当前热议!神似梅西男子成网红 被民众围堵合影:这也太像了
分析师称《阿凡达2》难以回本:卡梅隆标准定太高了
2199元 掌阅Smart Air Pro电纸书上架:8寸大屏、300PPI显示
前端工程化Vue-cli
天天微头条丨Python unittest数据处理ddt
前端CSS Flex布局8大重难点知识,收藏起来吧
世界新消息丨django10 分页器与Form组件
【全球新要闻】FreeSWITCH学习笔记:XML配置文件
天天即时:怀旧情怀拉满:宾得宣布将开发新款胶片相机
阿根廷夺冠“拯救”伊利 但“奶茅”光环渐黯
环球快讯:一加宣布与OPPO服务融合:12月底全面加入OPPO售后服务系统
东北将迎今冬以来最强降雪:持续时间最长、范围最广
世界速递!框架第九课---ajax补充说明,多对多三种创建方式,django内置序列化组件(drf前身),ORM批量操作数据(ORM操作优化),自定义分页器,f
WPF工控组态软件之温度计
每日播报!Iceberg在袋鼠云的探索及实践
每日关注!hibernate validate工具,小心你的姿势不对
PCIe 5.0 SSD终于满血了!读写都是14GB/s、容量8TB
热消息:蔚来遭遇225万美元数据勒索 官方声明
当前讯息:铃木“大G”!吉姆尼五门版无伪谍照:最多能塞进7个人
奇迹!女子手机从26楼掉落未摔坏 真身竟是这款手机
5499元 联合创新推出新款32英寸显示器:4K MiniLED屏、144Hz高刷
“非洲之王”拥抱新技术:传音首台折叠屏手机已通过蓝牙SIG认证
天天短讯!世界北极熊之都升温过快 已危及北极熊生存:吃不上饭了
天天热资讯!深度学习炼丹-数据处理和增强
世界热门:记录--可视化大屏-用threejs撸一个3d中国地图
Python操作Excel(openpyxl)
全球热点评!Html5 canvas创意特效合集
即时看!1月1日起:澳门私家车可经港珠澳大桥出入内地
观速讯丨巡游大巴太高 梅西险些撞上电缆!他带回阿根廷的大力神杯居然是复制品
天天短讯!中国联通科技人才占比已达30% 曾发话不能再用老眼光看电信行业
空难曾致346人死亡 波音737 Max飞机延期采用最新安全标准
每日观察!广州多个外卖平台下单后配送慢 平台:员工已是全负荷工作
世界视讯!数据结构堆(Heap)&排序&二叉树
今日播报!用好这个任务管理工具,轻松躲避职场明枪暗箭
世界今日报丨彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-登录与图形验证码(captcha)EP06
今日热闻!低代码:如何成为企业业务价值提升的一大利器?
热消息:Intel第二代独立显卡1年后见:要追上RTX 4070!
主页不刷新了 小红书崩了累坏网友:WiFi、流量疯狂切换
罗永浩称他的失败不是理想主义的错 是他们自己的错
世界热讯:吴京《流浪地球2》吃苹果皮:大年初一上映
世界要闻:中国移动千兆宽带用户已达2.4亿!你是其中之一吗?
安全信息流工具-中文安全RSS小程序
supervisor+gunicorn+uvicorn部署fastapi项目
天天实时:四年保质期囤货无压力!900压缩饼干8斤85元
天天热资讯!iPhone 15系列或重新划分机型组合:14 Plus太拉胯 要大改
一加11质感绝了!刘作虎给员工秀真机:围观群众都发出WOW
美国“显卡税”又推迟9个月:一旦征收 最多涨价25%
全球讯息:大无语 车主称理想L9半个月坏三次 充电口从电动变手动
天天关注:企业转型难?火山引擎数智平台提供数智升级新路径
焦点热门:Dubbo架构设计与源码解析(一) 架构设计