The full name of the SPI is the service Provider Interface. Ordinary developers may be unfamiliar because this is for vendors or plug-ins. A more detailed description is available in the Java.util.ServiceLoader documentation. The thought is actually the same as "Callback". The idea of "Callback" is that when we invoke the API, we can write a piece of logical code ourselves and pass it into the API, which is invoked within the API at the right time to achieve some degree of customization.
Typical is collections.sort (list<t> list,comparator< Super T> C) This method, its second parameter is an instance of implementing the comparator interface. We can write a class based on our own collation, implement this interface, and pass in this method, and the method will sort the list according to our rules.
To extend this idea, we use SPI to recreate the above example. The client writes its own collation into a class and packs it into a jar file, which must have a meta-inf directory and a services directory under it with a text file with the name of the interface as its full name: Java.util.Comparator.
--meta-inf
--services
--java.util.comparator
There is only one line of file contents:
Com.company1.ComparatorProvider
This line is the full name of the class that you implemented the comparator interface with the following code:
Package com.company1;
Import Java.util.Comparator;
Import Com.mycompany.myapp.MyItem; public class Comparatorprovider implements comparator<myitem>{@Override public int Compare (myitem O1, Myite
M O2) {//Based on name sort return O1.getname (). CompareTo (O2.getname ()); After compiling the package, put it in the class path of your main program.
Here's your main program://Search from the Meta-inf directory of all the jars in class path, find the right class and load it.
private static Serviceloader<comparator> Serviceloader = Serviceloader.load (Comparator.class);
public static void Main (string[] args) {list<myitem> myList = new arraylist<myitem> ();
Mylist.add (New myitem (2, "C", "HHH"));
Mylist.add (New myitem (3, "K", "Ooo"));
Mylist.add (New myitem (4, "D", "PPP"));
Mylist.add (New myitem (5, "B", "GGG"));
Showlist (myList);
Collections.sort (Mylist,getcompartor ());
Showlist (myList); @SuppressWarnings ("unchecked") Private statIC comparator<myitem> Getcompartor () {for (Comparator Service:serviceloader) {
Return (comparator<myitem>) service;
return null; }
Note that Serviceloader starts with just loading classes, instantiated to the first time. Class myitem and method showlist aren't important, so you don't have to care. You can follow this rule, write another sort of jar, and you can change your sorting rules at any time.
------------------------------
Recently saw some of the company's framework and some of the open source framework seen before some of the service discovery and access are using the Java SPI mechanism.
So simply summarize the idea of the Java SPI mechanism.
The abstract modules in our system often have many different implementations, such as the program of the log module, the XML parsing module, the JDBC module scheme, etc. Object-oriented design, we generally recommend that the module is based on interface programming between modules do not hard-code implementation classes. Once a specific implementation class is involved in the code, the pluggable principle is violated, and if you need to replace an implementation, you need to modify the code.
This requires a service discovery mechanism in order to realize that the module can not be dynamically specified in the program when it is assembled. The Java SPI provides a mechanism for finding a service implementation for an interface. A bit like the idea of the IOC is to move control of the assembly outside the program, which is particularly important in modular design.
The specific conventions of the Java SPI are as follows :
When the provider of the service provides an implementation of the service interface, create a file named after the service interface in the meta-inf/services/directory of the jar package. The file is a concrete implementation class that implements the service interface. When the external program assembles this module, it can find the specific implementation class name through the configuration file in the jar package meta-inf/services/, and load the instantiation to complete the injection of the module.
Based on such a convention, you can find the implementation class of the service interface well, without needing to make it in code.
JDK provides a service implementation lookup of a tool class: Java.util.ServiceLoader
Example
1.common-logging
The first façade interface for the log provided by Apache. Only interfaces, not implemented. The specific scenario is implemented by each provider, and the discovery log provider scans the Meta-inf/services/org.apache.commons.logging.logfactory configuration file to find the log to the business implementation class by reading the contents of the file. As long as our log implementation contains this file, and in the file to develop Logfactory factory interface implementation class can be.
2.jdbc
Before jdbc4.0, developers also needed to load drivers based on class.forname ("xxx"), JDBC4 also based on the SPI mechanism to discover driver providers that could be passed meta-inf/services/ Java.sql.Driver to expose the driver provider by specifying the implementation class in the file.
3. Write your own simple examples
Suppose there is a content search system, divided into display and search two modules. Presentation and search are based on interface programming. The implementation of the search may be based on a file system search, or it may be a database based search. The instance code is as follows
Search.java: Searching interface Java code package search; Import java.util.List; Import definition. Doc; Public interface Search {list<doc> search (String keyword); }
Filesearch.java: File system Search to achieve Java code package search; Import java.util.List; Import definition. Doc; public class FileSearch implements search {@Override public list<doc> search (String keyword) { SYSTEM.OUT.PRINTLN ("Now use file system search.) Keyword: "+ keyword); return null; } }
Databasesearch.java Java code Package search; Import java.util.List; Import definition. Doc; public class Databasesearch implements search {@Override public list<doc> search (String keyword) { SYSTEM.OUT.PRINTLN ("Now use database search.") Keyword: "+ keyword); return null; } }
Searchtest.java