SPI(Service Provide Interface)即服务提供接口规范,其功能是为了实现可插拔的服务提供,比如javax的validator框架就是借此实现的,java只是定义接口规范,具体实现方之一由hibernate提供。
名词解释
Service Implementer: 服务的实现
Service Provide: 服务的提供
Service Interface: 服务的接口
开发流程
-
定义服务接口(工程exchange-rate-api)
package com.baeldung.rate.spi;
import com.baeldung.rate.api.QuoteManager;
public interface ExchangeRateProvider {
QuoteManager create();
}
-
服务实现(工程exchange-rate-impl)
package com.baeldung.rate.impl;
import com.baeldung.rate.api.QuoteManager;
import com.baeldung.rate.spi.ExchangeRateProvider;
public class YahooFinanceExchangeRateProvider implements ExchangeRateProvider {
@Override
public QuoteManager create() {
return new YahooQuoteManagerImpl();
}
}
-
服务的提供或发布(工程exchange-rate-impl)
在META-INF/service目录下定义服务接口文件com.baeldung.rate.spi.ExchangeRateProvider,内容为服务实现com.baeldung.rate.impl.YahooFinanceExchangeRateProvider
com.baeldung.rate.impl.YahooFinanceExchangeRateProvider
-
服务调用
通过ServiceLoader.load()去加载调用
package com.baeldung.rate;
import com.baeldung.rate.exception.ProviderNotFoundException;
import com.baeldung.rate.spi.ExchangeRateProvider;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
public class ExchangeRate {
private static final String DEFAULT_PROVIDER = "com.baeldung.rate.spi.YahooFinanceExchangeRateProvider";
public static List<ExchangeRateProvider> providers() {
List<ExchangeRateProvider> services = new ArrayList<>();
ServiceLoader<ExchangeRateProvider> loader = ServiceLoader.load(ExchangeRateProvider.class);
loader.forEach(exchangeRateProvider -> {
services.add(exchangeRateProvider);
});
return services;
}
public static ExchangeRateProvider provider() {
return provider(DEFAULT_PROVIDER);
}
private static ExchangeRateProvider provider(String providerName) {
ServiceLoader<ExchangeRateProvider> loader = ServiceLoader.load(ExchangeRateProvider.class);
Iterator<ExchangeRateProvider> it = loader.iterator();
while (it.hasNext()) {
ExchangeRateProvider provider = it.next();
if (providerName.equals(provider.getClass().getName())) {
return provider;
}
}
throw new ProviderNotFoundException("Exchange Rate provider " + providerName + " not found");
}
}