简单的 ServiceLoader 示例

ServiceLoader 是一种简单易用的内置机制,用于动态加载接口实现。使用服务加载器 - 提供即时(但不是布线)的方法 - 可以在 Java SE 中构建简单的依赖注入机制。使用 ServiceLoader 接口和实现分离变得自然,程序可以方便地扩展。实际上,很多 Java API 都是基于 ServiceLoader 实现的

基本概念是

  • 在服务接口上运行
  • 通过 ServiceLoader 获取服务的实现
  • 提供服务的实现

让我们从界面开始,把它放在一个 jar 中,例如 accounting-api.jar

package example;

public interface AccountingService {

  long getBalance();
}

现在我们在名为 accounting-impl.jar 的 jar 中提供该服务的实现,其中包含服务的实现

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

  public long getBalance() {
    return balanceFromDB();
  }

  private long balanceFromDB(){
    ...
  }
}

此外,accounting-impl.jar 包含一个文件,声明此 jar 提供了 AccountingService 的实现。该文件必须具有以 META-INF/services/开头的路径,并且必须与接口的完全限定名称具有相同的名称 :

  • META-INF/services/example.AccountingService

该文件的内容是实现的完全限定名称:

example.impl.DefaultAccountingService

鉴于两个 jar 都在程序的类路径中,消耗 AccountingService,可以使用 ServiceLauncher 获取服务的实例

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
AccountingService service = loader.next();
long balance = service.getBalance();

由于 ServiceLoaderIterable,它支持多个实现提供程序,程序可以从中选择:

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)
for(AccountingService service : loader) {
   //...
}

请注意,在调用 next() 时,将始终创建一个新实例。如果要重用实例,则必须使用 ServiceLoader 的 iterator() 方法或 for-each 循环,如上所示。