Introduction to the

The full name of SPI is Service Provider Interface. A Service usually refers to an Interface or abstract class. The Service Provider implements the Interface or abstract class, and a third party implements the Interface to provide specific services. SPI provides a mechanism for dynamically extending applications, often as extensions to framework services or as alternative service components.

Mechanism of SPI

  • Create a file in the resources/ meta-INF /services/ directoryFully qualified service nameNamed the file whose content isFully qualified name of the concrete implementation class of the service, a file can write concrete implementation classes for multiple services
  • Use the ServiceLoader class to dynamically load the concrete implementation classes of the service
  • The service concrete implementation class must have a constructor that takes no arguments

use

Define an interface or abstract class

public interface MessageService {
    String getMessage(a);
}
Copy the code

Implementing an interface

public class AMessageService implements MessageService {
    @Override
    public String getMessage(a) {
        return "Hello from module A"; }}Copy the code
public class BMessageService implements MessageService {
    @Override
    public String getMessage(a) {
        return "Welcome from b"; }}Copy the code

Create an SPI description file

Note the directory structure as shown below:

You can use auto-service launched by Google, which can easily help us generate corresponding description files. The usage is very simple

Use auto – service:

  1. Rely onImplementation 'com. Google. Auto. Services: auto - service: 1.0 -rc3'
  2. Use annotations in the Service implementation class@AutoService
@AutoService(MessageService.class)
public class BMessageService implements MessageService {
    @Override
    public String getMessage(a) {
        return "Welcome from b"; }}Copy the code

Invoking specific services

Use the ServiceLoader to load the specific service class and then iterate through the specific implementation class. The ServiceLoader actually reads the contents of the file in the meta-info /services directory and instantiates it.

        ServiceLoader<MessageService> serviceServiceLoader = ServiceLoader.load(MessageService.class);
        for (MessageService messageService : serviceServiceLoader) {
            Log.d("auto service"."msg:" + messageService.getMessage());
        }
Copy the code

advantages

Only the service interface is provided, and the specific service is realized by other components. The interface and the specific implementation are separated. At the same time, the system ServiceLoader can get the collection of these implementation classes, and unified processing.

disadvantages

  • In Java, SPI is shipped with jars, and each different JAR can contain a set of SPI configurations, whereas on Android, applications will eventually merge all jars when they are built, which can easily cause the same SPI conflicts. Common problems are DuplicatedZipEntryException anomalies
  • SPI configuration information is read at runtime from the JAR package. Since APK is signed, signature verification takes time and results in performance loss when reading from the JAR
  • Loading class instances at run time through reflection incurs a performance penalty

conclusion

SPI is almost not used in Android projects. If you want to achieve communication between components and reduce performance loss, you can use APT to produce corresponding Service at compile time, and then obtain the instance of Service through dependency injection. However, we will use SPI technology in APT, so I think it is necessary to talk about SPI first.

Refer to the demo