spi是Service Provider Interface的缩写。使用spi技术可以通过修改配置的方式,更换程序中某个接口的实现类,从而改变程序行为。spi的用法如下:

  1. 定义接口。
package com.foo.bar.service;
public interface Foo {
    String foo(String name);
}

  1. 编写接口实现类。
package com.foo.provider.v1;
public class FooServiceProvider implements Foo {
    String foo(String name) {
        return "hello" + name;
    }
}

package com.foo.provider.v2;
public class FooServiceProvider implements Foo {
    String foo(String name) {
        return String.format("Hello, %s!", name);
    }
}

  1. 建立spi文件。

建立文件META-INF\services\com.foo.bar.service.FooService,写入下面两行:

com.foo.bar.provider.v1.FooServiceProvider
com.foo.bar.provider.v2.FooServiceProvider

  1. 加载接口实现类。
import java.util.ServiceLoader;
import com.foo.bar.service.FooService;

public class App {
  public static void main(String[] args) {
  for (FooService provider: ServiceLoader.load(FooService.class)) {
    System.out.println(provider.foo("Foo");
  }
}

  1. 在Spring中使用spi。
public interface BarService {
  public String bar(String abc);
}

public class BarServiceProvider {
  public String bar(String abc) { return ""; }
}

public class Demo {
  private static ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfiguration.class);

  public static void main(String[] args) {
    BarService dictionary = ctx.getBean(BarService.class);
    System.out.println("Book: " + dictionary.bar("book"));
  }
}

@Configuration
public class AppConfiguration {
  @Bean
  public BarService barService(ServiceLoader<Service> loader) {
    return new Service(loader);
  }

  @Bean
  public ServiceLoaderFactoryBean dictionaryServiceLoaderFactory() {
    ServiceLoaderFactoryBean factoryBean = new ServiceLoaderFactoryBean();
    factoryBean.setServiceType(BarService.class);
    return factoryBean;
  }
}

  1. 对JDBC使用spi。

编辑文件META-INF/services/java.sql.Driver,加入所需要的驱动类。

参考资料

11-17 05:31