Ceci est similaire à la fonction SPI en Java. Lorsque SpringBoot démarre, il lira les fichiers META-INF/spring.factories
sous tous les packages 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
中找到了这个文件
那么文件中的两个实现类也会被实例化;加上上面4个总共有6个
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
spring.factories
🎜🎜 Analyse du code source🎜🎜Démarrez SpringApplication et regardez la méthode de construction🎜rrreee🎜La méthode getSpringFactoriesInstances(ApplicationContextInitializer.class)
est utilisée pour obtenir l'instance de classe spécifiée dans Spring et lors de son obtention, elle est utilisée. est basé sur la lecture de l'intégralité du chemin du fichier dans le projet. Il s'agit du contenu de META-INF/spring.factories
qui instancie la classe d'instance correspondante 🎜🎜Par exemple, le ApplicationContextInitializer
; > voici une interface, elle doit donc être instanciée. Quelles autres classes d'implémentation doivent être transformées ? Recherchez ensuite le fichier META-INF/spring.factories
; nous avons ensuite trouvé ce fichier dans le package spring-boot:2.1.0
jar🎜🎜🎜🎜Lisez que la classe d'implémentation qui doit être instancié est 🎜rrreee🎜Et j'ai également trouvé ce fichier dans spring-boot-autoconfigure-2.1.0.RELEASE.jar
🎜🎜🎜🎜Ensuite, les deux classes d'implémentation dans le fichier seront également instanciées ; plus les 4 ci-dessus, il y a un total de 6 🎜rrreee🎜 🎜🎜Oui Voyez que non seulement les classes d'instance de org.springframework.context.ApplicationContextInitializer
sont analysées, mais qu'elles sont toutes analysées et enregistrées. D'autres classes doivent être instanciées la prochaine fois. directement à partir de la mémoire ; 🎜🎜Après avoir obtenu la classe d'instance dans le processus ci-dessus, l'étape suivante est le processus d'instanciation 🎜rrreee🎜La méthode createSpringFactoriesInstances
est le processus de création d'une instance, vous pouvez le voir ; en passant Entrez la classe d'interface correspondante org.springframework.context.ApplicationContextInitializer
; puis instanciez la classe d'implémentation correspondante trouvée ci-dessus 🎜rrreee🎜S'il n'y a rien de spécial à expliquer sur le processus d'instanciation ;🎜🎜Il y a ; une méthode AnnotationAwareOrderComparator.sort(instances);
ci-dessus qui est utilisée pour trier toutes les instances ; la classe d'implémentation doit implémenter l'interface Ordered
; La priorité est plus élevée🎜spring.factories
, nous pouvons alors utiliser cette fonctionnalité pour atteindre nos propres objectifs ;🎜🎜Par exemple, nous pouvons également écrire une classe d'implémentation d'interface de la classe ApplicationContextInitializer
. 🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!