SPI机制

SPI其实就是一种约定好规范,规定好在classpath下的META-INF/services/路径下,放置指定接口的指定实现类,然后java提供了ServiceLoader类,这个类会去读取这个文件,然后通过文件中指定的接口实现类,然后class.forName()加载这个类。
总是:就是javase约定好规范,然后就能通过serviceLoader,来找到具体的实现类。
这样,可以,直接用接口进行调用,然后谁想实现他们的功能,谁就去实现这个接口,然后把这个接口实现类放到META-INF/services/路径就好了。

这里有个网上的例子:

public interface IShout {
    void shout();
}
public class Dog implements IShout {
    @Override
    public void shout() {
        System.out.println("wang wang");
    }
}
public class Cat implements IShout {

    @Override
    public void shout() {
        System.out.println("miao miao");
    }
}
META-INF/services/org.foo.demo.IShout文件内容
org.foo.demo.Dog
org.foo.demo.Cat

测试
public class SPIMain {
    public static void main(String[] args) {
        ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class);
        for (IShout s : shouts) {
            s.shout();
        }
    }
}

既然是一个约定好的规范,那么,自然,你也可以约定好一个规范,然后自己做一个类似serviceLoader的加载器,然后去加载实现类就可以了,只要,让别人遵守这个规范就好了。

比如,dubbo:
对于Protocal的接口,提供实现类:
/META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
然后通过自己的加载器,加载就完了。
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

dubbo为什么要自己实现spi呢?
因为,dubbo需要一个接口提供多个实现类,然后通过注解的方式,指定使用哪个实现类。
比如,它的/META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件内容是:

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
http=com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

以properties的方式,对实现类提供了一个标识符,然后通过@SPI("dubbo")这样的方式,实现加载指定的实现类,而这个方式,是java自带的spi做不到的。

@SPI("dubbo")  
public interface Protocol {  
    int getDefaultPort();  
    @Adaptive  
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;  
    @Adaptive  
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;  
    void destroy();  
} 

参考:https://juejin.im/post/5af952fdf265da0b9e652de3

转载于:https://www.jianshu.com/p/1a301ae3c650

猜你喜欢

转载自blog.csdn.net/weixin_34080571/article/details/91202644