spi是Service Provider Interface的缩写。使用spi技术可以通过修改配置的方式,更换程序中某个接口的实现类,从而改变程序行为。spi的用法如下:
- 定义接口。
package com.foo.bar.service;
public interface Foo {
String foo(String name);
}
- 编写接口实现类。
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);
}
}
- 建立spi文件。
建立文件META-INF\services\com.foo.bar.service.FooService,写入下面两行:
com.foo.bar.provider.v1.FooServiceProvider
com.foo.bar.provider.v2.FooServiceProvider
- 加载接口实现类。
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");
}
}
- 在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;
}
}
- 对JDBC使用spi。
编辑文件META-INF/services/java.sql.Driver,加入所需要的驱动类。
参考资料