これは Java の SPI 関数に似ており、SpringBoot が起動すると、すべての jar の下にある META-INF/spring.factories
ファイルが読み取られます。パッケージ;
そして、ファイル内のインターフェイス/抽象クラスに対応する実装クラスをマップし、必要に応じて対応する実装クラスをインスタンス化します
##ソース コードを分析して見てみましょう spring.factories使用シナリオ
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 パッケージ
にあります。
インスタンス化する必要がある実装クラスが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 にあることを確認してください
#ファイル内の 2 つの実装クラスもインスタンス化され、上記の 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; }
Method
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 によって返される値が小さいほど、優先順位が高くなります。
Usagespring.factories
の使用法を理解した後、この機能を使用して次のことができます。独自の目的を達成します。
の実装クラスを作成することもできます。
以上がSpringBoot spring.factories 読み込みタイミングのソースコード解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。