SPI (Service Provider Interface) est un mécanisme de découverte de services intégré au JDK, qui peut être utilisé pour activer des extensions de framework et des composants de remplacement. Il est principalement utilisé pour le développement dans des frameworks, tels que Dubbo, Spring, et Common-Logging , JDBC, etc. adoptent le mécanisme SPI et utilisent différentes implémentations pour la même interface afin de la fournir à différents utilisateurs, améliorant ainsi l'évolutivité du framework.
Le SPI intégré de Java analyse le fichier nommé avec le nom complet de l'interface dans le répertoire META-INF/services/ du package classPath et jar via la classe java.util.ServiceLoader, et charge l'interface spécifiée dans le fichier Implémentez la classe pour terminer l'appel.
public interface VedioSPI { void call(); }
public class Mp3Vedio implements VedioSPI { @Override public void call() { System.out.println("this is mp3 call"); } }
public class Mp4Vedio implements VedioSPI { @Override public void call() { System.out.println("this is mp4 call"); } }
Créez un nouveau répertoire META-INF/services/ dans le répertoire source du projet et créez com.skywares.fw. fichiers juc.spi .VedioSPI.
public class VedioSPITest { public static void main(String[] args) { ServiceLoader<VedioSPI> serviceLoader =ServiceLoader.load(VedioSPI.class); serviceLoader.forEach(t->{ t.call(); }); } }
Description : Java implémente spi via ServiceLoader pour trouver les classes d'outils fournies par le service.
Ce qui précède n'est qu'un exemple simple pour implémenter la fonction SPI intégrée de Java. Le principe d'implémentation est que ServiceLoader est une classe d'outils Java intégrée pour trouver des interfaces fournissant des services. Il recherche les interfaces fournissant des services en appelant la méthode load(), et enfin parcourt pour accéder aux classes d'implémentation des interfaces fournissant des services une par une. .
Vous pouvez trouver dans le code source :
La classe ServiceLoader elle-même implémente l'interface Iterable et y implémente la méthode itérateur. L'implémentation de la méthode itérateur appelle la méthode dans la classe interne LazyIterator après l'analyse. le fichier d'interface du fournisseur de services. Le résultat final est renvoyé dans l'itérateur et l'accès direct à la classe d'implémentation d'interface fournie par le service n'est pas pris en charge.
Les fichiers correspondants à toutes les interfaces des fournisseurs de services sont placés dans le répertoire META-INF/services/. Le type final détermine que le répertoire PREFIX ne peut pas être modifié.
Bien que l'idée du mécanisme SPI fourni par Java soit très bonne, elle présente également des inconvénients correspondants. Les détails sont les suivants :
Les méthodes intégrées de Java ne peuvent être obtenues que par traversée
L'interface du fournisseur de services doit être placée dans le répertoire META-INF/services/.
Compte tenu des problèmes existant dans le spi de Java, le mécanisme SPI de Spring suit l'idée du SPI, mais l'étend et l'optimise.
Spring SPI suit l'idée de conception de Java SPI Spring utilise spring.factories pour implémenter le mécanisme SPI, qui peut fournir l'évolutivité du framework Spring sans modifier le code source de Spring.
Exemple Spring
Interface de définition
public interface DataBaseSPI { void getConnection(); }
Implémentation associée
#DB2实现 public class DB2DataBase implements DataBaseSPI { @Override public void getConnection() { System.out.println("this database is db2"); } } #Mysql实现 public class MysqlDataBase implements DataBaseSPI { @Override public void getConnection() { System.out.println("this is mysql database"); } }
1 Dans le répertoire META-INF du projet, ajoutez le fichier spring.factories
2. Remplissez les informations d'interface pertinentes, le contenu. est le suivant
com.skywares.fw.juc.springspi.DataBaseSPI = com.skywares.fw.juc.springspi.DB2DataBase, com.skywares.fw.juc.springspi.MysqlDataBase
Description Plusieurs implémentations sont séparées par virgules.
Classe de test associée
public class SpringSPITest { public static void main(String[] args) { List<DataBaseSPI> dataBaseSPIs =SpringFactoriesLoader.loadFactories(DataBaseSPI.class, Thread.currentThread().getContextClassLoader()); for(DataBaseSPI datBaseSPI:dataBaseSPIs){ datBaseSPI.getConnection(); } } }
Résultats de sortie
À partir de l'exemple, nous pouvons voir que Spring utilise spring.factories pour implémenter SPI et que Java implémente SPI. Cependant, la méthode spi de Spring est spécifiquement optimisée pour le spi de Java. est la suivante :
Java SPI est un service fournissant une interface correspondant à un fichier de configuration. Le fichier de configuration stocke toutes les classes d'implémentation de l'interface actuelle. Plusieurs interfaces fournissant des services correspondent à plusieurs fichiers de configuration. ;
Spring factory SPI est un fichier de configuration spring.factories qui stocke plusieurs interfaces et les classes d'implémentation correspondantes. Le nom complet de l'interface est utilisé comme clé et la classe d'implémentation est utilisée comme valeur à configurer. les classes d'implémentation sont séparées par des virgules, seul spring fabrique un fichier de configuration.
Alors, comment Spring implémente-t-il SpI en chargeant spring.factories ? Nous pouvons analyser plus en détail via le code source ?
Description : loadFactoryNames analyse le nom complet de la classe d'implémentation de l'interface spécifiée dans le fichier spring.factories. L'implémentation spécifique est la suivante :
.Description : obtenez le chemin du fichier META-INF/spring.factories dans tous les packages jar et renvoyez-le sous forme de valeur d'énumération. Parcourez le chemin du fichier spring.factories, chargez et analysez un par un, intégrez le nom de classe d'implémentation du type factoryClass, obtenez le nom de classe complet de la classe d'implémentation, puis effectuez l'opération d'instance de la classe. comme suit :
Explication : L'instanciation est L'initialisation correspondante est obtenue par réflexion.
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!