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/ directory
Fully qualified service name
Named 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:
- Rely on
Implementation 'com. Google. Auto. Services: auto - service: 1.0 -rc3'
- 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