Java中的SPI(Service Provider Interface)

Posted by 李小武 on May 23, 2013

SPI(Service Provider Interface),一个Java内置的标准,允许不同的开发者去实现某个特定的服务。

A service is a well-known set of interfaces and (usually abstract) classes. A service provider is a specific implementation of a service. The classes in a provider typically implement the interfaces and subclass the classes defined in the service itself. Service providers can be installed in an implementation of the Java platform in the form of extensions, that is, jar files placed into any of the usual extension directories. Providers can also be made available by adding them to the application’s class path or by some other platform-specific means.

下面举个例子:

加入有个厂商有个播放器应用,只支持mp3格式播放,同时这个厂商提供了SPI接口,现在你要扩展这个播放器,使其支持wma和ogg格式的音乐播放。

SPI定义如果:

public interface DecodeAudio{
    void decode(File file);
    String getFileType();
}

播放器代码:

public class Player{

    private  ServiceLoader<DecodeAudio> decoders = ServiceLoader.load(DecodeAudio.class);

    public void play(File file){
        for(DecideAudio  decoder : decoders){
			if(decoder.getFileType.equals(file.getextEnsion())){
                decoder.decode(file);
                return;
            }
		}
        throw new Exception("文件格式不支持");
    }
}

在我们的工程中,先要1)引入这个厂商提供的jar包。

然后2)实现服务接口DecodeAudio,实现两种格式音乐的播放:

public interface WmaDecodeAudio{
    void decode(File file){
        // 具体播放细节
    }
    String getFileType(){ return "wma" }
}


public interface OggDecodeAudio{
    void decode(File file){
        // 具体播放细节
    }
    String getFileType(){ return "ogg" }
}

接下来,3)在自己的工程目录META-INF/services下创建一个DecodeAudio类全名(如:cn.cmp.DecodeAudio)的文件

META-INF/services/cn.cmp.DecodeAudio

在这个文件中,注册自己实现的两个格式的服务实现:

cn.lichengwu.WmaDecodeAudio #wma格式支持
cn.lichengwu.OggDecodeAudio #ogg格式支持

这样,把自己写的项目打包,就是一个可以支持wma和ogg播放的播放器了。

关于META-INF/services的文件格式:

  • 文件名字必须是SPI类的全名
  • 文件的内容是SPI服务具体实现类的全名
  • 文件采用UTF-8编码
  • #来表示注释

关于SPI接口以及实现类:

实现类必须要有一个无参的构造方法,ServiceLoader支持懒加载方式,只有当需要的时候,才去加载服务的实现类。

参考资料:http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html