Java SPI(Service Provider Interface)
(1)接口
public interface SPIService {
public void printService();
}
(2)接口实现1
public class SPIServiceImpl implements SPIService {
public void printService() {
System.out.println("Hello World");
}
}
(3)接口实现2
public class SPIServiceImpl2 implements SPIService {
public void printService() {
System.out.println("Hello World2");
}
}
(4)接口实现2
public class SPIServiceImpl3 implements SPIService {
public void printService() {
System.out.println("Hello World3");
}
}
(5)在resource目录下建立META-INF/services目录,建立接口的全路径名文件(这里是gdut.ff.spi.SPIService),在文件里以分行符分隔接口实现类的全路径名。
(6)Main方法
import java.util.ServiceLoader;
public class SPIServiceMain {
public static void main(String[] args) {
ServiceLoader<SPIService> serviceLoader = ServiceLoader.load(SPIService.class);
for (SPIService spiService:serviceLoader) {
spiService.printService();
}
}
}
java.util.ServiceLoader可以获取接口的全部实现,具体调用哪个实现是用户在META-INF/services中配置。
Dubbo SPI
(1)在接口上添加注解@SPI
import org.apache.dubbo.common.extension.SPI;
@SPI("spiServiceImpl")
public interface SPIService {
public void printService();
}
(2)在META-INF/dubbo/internal文件夹下建立全路径名配置文件,内容如下
spiServiceImpl=gdut.ff.spi.SPIServiceImpl
(3)Main方法:通过ExtensionLoader获取接口SPIService.class的默认实现
public class SPIServiceMain {
public static void main(String[] args) {
SPIService defaultExtension = ExtensionLoader.getExtensionLoader(SPIService.class).getDefaultExtension();
defaultExtension.printService();
}
}
Java SPI 和 Dubbo SPI 对比
(1) Java SPI会一次性实例化所有拓展点的实现,而Dubbo SPI并不会立即全部初始化。
(2) Dubbo SPI实现了IoC和AOP机制。
(3) Dubbo SPI兼容Java SPI的配置方式和配置内容,在Dubbo启动的时候,会扫描META-INF/services/,META-INF/dubbo/,META-INF/dubbo/internal/三个目录
拓展点注解 @SPI
(1)@SPI可以使用在类、接口和枚举类上。
(2)标志这是Dubbo SPI接口。
(3)SPI注解有一个value属性,可以通过这个属性设置这个接口的默认实现类。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
/**
* 默认实现类名称
*/
String value() default "";
}
拓展点自适应注解 @Adaptive
(1)@Adaptive注解可以标记在类、接口、枚举和方法上。
(2)使用@Adaptive注解,可以动态地通过URL中的参数来确定具体使用的实现类,从而解决了自动加载中的实例注入问题。
(3)当传递的参数URL没有参数key可以匹配@Adaptive的value数组的某一个值,就会使用@SPI("XXX")默认实现。
(4)当传递的参数URL有参数key可以匹配@Adaptive的value数组的某一个值(顺序是key依次匹配),就使用该key对应的value值。查找该value值在配置文件(META-INF/dubbo/internal/目录下)对应的实现类。
(5)当在某个实现类上加了@Adaptive注解,优先级最高,无论默认实现@SPI的值是什么和URL传递了什么参数,都会直接调用带有@Adaptive注解的类。
(6)方法级别注解会生成和编译动态实现类,而类级别的注解不会生成动态类。
(7)会缓存两个与@Adaptive有关的对象,Adaptive具体实现类的Class类型缓存在cachedAdaptiveClass中;Class的具体实例化对象缓存在cachedAdaptiveInstance中。
@SPI("spiServiceImpl")
public interface SPIService {