SPI principle and actual combat of SPI in Android

1. Background

Do you have any doubts before opening the question, that is, with the development and growth of the business, our project structure and code volume are getting larger and larger, intertwined, you have me, I am

With you in the middle, the division of labor in the project structure is not very clear, and the responsibilities are not clear. If there are urgent problems online that need to be checked, we may be in a hurry, and sometimes we don’t know how to ask.

The problem appears in that module, which leads to low troubleshooting efficiency, and is not conducive to project review and clarification of responsibilities, or when the boss wants to see some data such as business success rate, service success rate, etc.

At that time, we may write it directly in the code for convenience. As the business continues to iterate, the new colleague who takes over may rack his brains. What exactly does this code do and why?

It should be written here (maybe this code has no actual business meaning at all, it is just a buried point or data statistics code) and other issues, today we will introduce it to you grandly.

Introduce a new solution to solve these problems, this solution is SPI, the full name is Service Provider Interface, of course, you may say that there are other solutions, yes, indeed

There are other plans, all roads lead to Rome, OK, let's stop talking nonsense and get to the point.

2. What is SPI

SPI (Service Provider Interface) is a set of APIs provided by JDK to be implemented or extended by third parties. It is a service registration discovery mechanism at the JVM level.

Can be used to enable framework extensions and replace components, mainly used by framework developers. The main idea of ​​the SPI mechanism is to move the control of the assembly out of the program.

This mechanism is particularly important in design, and its core idea is decoupling.

2.1: SPI Overall Mechanism

As shown in Figure 1 below:

figure 1

Java SPI is actually a dynamic loading mechanism implemented by the combination of "interface-based programming + strategy mode + configuration file". The core idea is service registration + service discovery

2.2: Difference between SPI and API

So when it comes to this, many people may have questions, what is the difference between this and API calls, OK, in order to explain this issue more clearly, we use specific diagrams to illustrate

SPI与API区别:

API

图2所示

图2

SPI

图3所示

图3

一般模块之间通信基本上都是通过接口,那我们在服务调用方和服务实现方(也称服务提供者)之间引入一个“接口概念”。

当实现方提供了接口和实现,我们可以通过调用实现方的接口从而拥有实现方给我们提供的能力,这就是 API ,这种接口和实现都是放在实现方的。

接口和实现方属于同一个模块,密切不可分割。

当接口存在于调用方这边时,就是 SPI ,由接口调用方确定接口规则,然后由不同的具体业务去根据这个规则对这个接口进行实现,从而提供服务,

举个通俗易懂的例子:一个电脑制造公司,设计好了充电器标准图纸以后,那么接下来就可以把这个图纸分发给不同的厂商去生产,最后只有严格按

照图纸要求,就可以生产合格的商品。

通过上面的图2和图3以及配合上面的文字介绍,相信大家应该很非常清楚API和SPI的区别了.

3.SPI作用

SPI的发现能力是不需要依赖于其他类库,主要实现方式是:

  • java.util.ServiceLoader#load JDK自身提供的加载能力

最重要的作用就是:解耦

4.实现原理

4.1: 源码分析

public final class ServiceLoader<S>

implements Iterable<S>

{

//配置文件所在的包目录路径

private static final String PREFIX = "META-INF/services/";

// 接口名称

private final Class<S> service;

// 类加载器

private final ClassLoader loader;

// The access control context taken when the ServiceLoader is created

// Android-changed: do not use legacy security code.

// private final AccessControlContext acc;

//providers就是不同实现类的缓存,key就是实现类的全限定名,value就是实现类的实例

private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

// //内部类LazyIterator的实例

private LazyIterator lookupIterator;

public void reload() {

providers.clear();

lookupIterator = new LazyIterator(service, loader);

}

private ServiceLoader(Class<S> svc, ClassLoader cl) {

service = Objects.requireNonNull(svc, "Service interface cannot be null");

loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;

// Android-changed: Do not use legacy security code.

// On Android, System.getSecurityManager() is always null.

// acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;

reload();

}

private static void fail(Class<?> service, String msg, Throwable cause)

throws ServiceConfigurationError

{

throw new ServiceConfigurationError(service.getName() + ": " + msg,

cause);

}

Guess you like

Origin blog.csdn.net/qq_18757557/article/details/128551981
SPI
Recommended