Maison  >  Article  >  Java  >  SpringBoot spring.factories chargement de l'analyse du code source du timing

SpringBoot spring.factories chargement de l'analyse du code source du timing

WBOY
WBOYavant
2023-05-17 21:31:041346parcourir

Le rôle de spring.factories

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.0jar包中找到了这个文件

SpringBoot spring.factories chargement de lanalyse du code source du timing

读取到需要实例化的实现类为

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中找到了这个文件

SpringBoot spring.factories chargement de lanalyse du code source du timing

那么文件中的两个实现类也会被实例化;加上上面4个总共有6个

org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

SpringBoot spring.factories chargement de lanalyse du code source du timing

可以看到不仅仅只是把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

et enregistrez les fichiers dans Les classes d'implémentation correspondant aux interfaces/classes abstraites sont mappées ensemble, et les classes d'implémentation correspondantes peuvent être instanciées si nécessaire🎜🎜Analysons le code source et voyons les scénarios d'utilisation de 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.0jar🎜🎜SpringBoot spring.factories chargement de l'analyse du code source de synchronisation🎜🎜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🎜🎜SpringBoot spring.factories chargement de l'analyse du code source de synchronisation🎜🎜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🎜SpringBoot spring.factories chargement de l'analyse du code source du timing 🎜🎜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🎜

Utilisation

🎜Après avoir connu l'utilisation de 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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer