什么是SPI

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。SPI是一种动态替换发现的机制, 比如有个接口,想运行时动态的给它添加实现,你只需要添加一个实现。我们经常遇到的就是java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,mysql和postgresql都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。
//省略使用样例

Mysql DriverManager实现

在DriverManager中有一个静态代码块如下:

  1. static {
  2. loadInitialDrivers();
  3. println("JDBC DriverManager initialized");
  4. }

loadInitialDrivers用法用到了SPI工具类ServiceLoader:

  1. public Void run() {
  2. ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
  3. Iterator<Driver> driversIterator = loadedDrivers.iterator();
  4. /* Load these drivers, so that they can be instantiated.
  5. * It may be the case that the driver class may not be there
  6. * i.e. there may be a packaged driver with the service class
  7. * as implementation of java.sql.Driver but the actual class
  8. * may be missing. In that case a java.util.ServiceConfigurationError
  9. * will be thrown at runtime by the VM trying to locate
  10. * and load the service.
  11. *
  12. * Adding a try catch block to catch those runtime errors
  13. * if driver not available in classpath but it's
  14. * packaged as service and that service is there in classpath.
  15. */
  16. try{
  17. while(driversIterator.hasNext()) {
  18. driversIterator.next();
  19. }
  20. } catch(Throwable t) {
  21. // Do nothing
  22. }
  23. return null;
  24. }

遍历使用SPI获取到的具体实现,实例化各个实现类。在遍历的时候,首先调用driversIterator.hasNext()方法,这里会搜索classpath下以及jar包中所有的META-INF/services目录下的java.sql.Driver文件,并找到文件中的实现类的名字,此时并没有实例化具体的实现类。