这篇文章主要介绍“SpringBoot spring.factories加载时机源码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot spring.factories加载时机源码分析”文章能帮助大家解决问题。
spring.factories作用
这个类似于Java中的SPI功能,SpringBoot启动的时候会读取所有jar包下面的meta-inf/spring.factories
文件;
并且将文件中的 接口/抽象类 对应的实现类都对应起来,并在需要的时候可以实例化对应的实现类
下面我们来分析一下源码看看spring.factories
的使用场景
源码解析
启动SpringApplication,看看构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setinitializers((Collection) getSpringFactoriesInstances( ApplicationContextinitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
其中方法getSpringFactoriesInstances( ApplicationContextinitializer.class)
是用于获取Spring中指定类实例用的;并且获取的时候是根据读取整个项目中文件路径为meta-inf/spring.factories
中的内容实例化对应的实例类的;
例如这里的ApplicationContextinitializer
是一个接口,那么应该实例化哪些他的实现类呢?那就找meta-inf/spring.factories
文件 ; 那么我们在spring-boot:2.1.0
jar包中找到了这个文件
读取到需要实例化的实现类为
org.springframework.boot.context.ConfigurationWarningsApplicationContextinitializer,\ org.springframework.boot.context.ContextIdApplicationContextinitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextinitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextinitializer
并且还在spring-boot-autoconfigure-2.1.0.RELEASE.jar
中找到了这个文件
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextinitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
可以看到不仅仅只是把org.springframework.context.ApplicationContextinitializer
的实例类解析了出来;而是所有的都解析了出来并且保存下来了.下次其他的类需要被实例化的时候就可以直接从内存里面拿了;
上面过程拿到了实例类之后,接下来就是实例化的过程了
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
方法createSpringFactoriesInstances
就是创建实例的过程;可以看到传入了对应的接口类org.springframework.context.ApplicationContextinitializer
;接下来就会实例化 上面找到了对应的实现类;
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.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }
实例化的过程如果,没有什么特别需要讲解的;
上面有个方法 AnnotationAwareOrderComparator.sort(instances);
是用来排序所有实例的; 实现类需要实现 接口Ordered
; getorder返回的值越小,优先级更高
用法
知道spring.factories
的用法之后, 那么我们就可以利用这个特性实现自己的目的;
例如我们也可以写一个接口类ApplicationContextinitializer
的实现类。
关于“SpringBoot spring.factories加载时机源码分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程之家行业资讯频道,小编每天都会为大家更新不同的知识点。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。