Java SPI机制

有这样的一个应用场景,在某个JAR包内,有一个接口IA,然后有3个IA接口的具体实现类,分别是AIA,BIA,CIA。

那么如果在该JAR包内其他的类中使用接口IA的时候,硬编码IA对象对应的具体实现类,就会导致非常不灵活。这就是SPI机制产生的场景由来。


一、SPI机制概念
SPI的全称是Service Provider Interface。

简单来说,SPI机制提供了一个表达接口和其具体实现类之间的绑定关系的方案。具体是在JAR包的"META-INF/services/"目录下建立一个文件,文件名是接口的全限定名,文件的内容可以有多行,每行都是该接口对应的具体实现类的全限定名。


二、使用例子
2.1、 commons-logging中的例子

在commons-logging:commons-logging:1.1包中有个LogFactory抽象类(全限定名是"org.apache.commons.logging.LogFactory"),在其中有个静态方法

public static LogFactory getFactory() throws LogConfigurationException

用于获取一个默认的LogFactory实例。


在该方法中,有一段Java代码片段如下:
if(factory == null) {
                if(isDiagnosticsEnabled()) {
                    logDiagnostic("[LOOKUP] Looking for a resource file of name [META-INF/services/org.apache.commons.logging.LogFactory] to define the LogFactory subclass to use...");
                }


                try {
                    InputStream names1 = getResourceAsStream(contextClassLoader, "META-INF/services/org.apache.commons.logging.LogFactory");
                    if(names1 != null) {
                        BufferedReader name;
                        try {
                            name = new BufferedReader(new InputStreamReader(names1, "UTF-8"));
                        } catch (UnsupportedEncodingException var7) {
                            name = new BufferedReader(new InputStreamReader(names1));
                        }


                        value = name.readLine();
                        name.close();
                        if(value != null && !"".equals(value)) {
                            if(isDiagnosticsEnabled()) {
                                logDiagnostic("[LOOKUP]  Creating an instance of LogFactory class " + value + " as specified by file \'" + "META-INF/services/org.apache.commons.logging.LogFactory" + "\' which was present in the path of the context" + " classloader.");
                            }


                            factory = newFactory(value, baseClassLoader, contextClassLoader);
                        }
                    } else if(isDiagnosticsEnabled()) {
                        logDiagnostic("[LOOKUP] No resource file with name \'META-INF/services/org.apache.commons.logging.LogFactory\' found.");
                    }
                } catch (Exception var8) {
                    if(isDiagnosticsEnabled()) {
                        logDiagnostic("[LOOKUP] A security exception occurred while trying to create an instance of the custom factory class: [" + var8.getMessage().trim() + "]. Trying alternative implementations...");
                    }
                }
}


这段代码的意思就是说使用SPI机制,在Jar包的"META-INF/services/"目录下查找一个文件名为"org.apache.commons.logging.LogFactory"的文件,在文件中可以配置默认要使用的LogFactory具体实现类的全限定名。


2.2、自己的例子

现在有以下类层次结构

Java SPI机制_第1张图片

IA的内容如下:

package spi;

public interface IA {
    void doIt();
}

AIA的内容如下:

package spi;

public class AIA implements IA {
    public void doIt() {
        System.out.println("doIt In AIA");
    }
}

BIA的内容如下:

package spi;

public class BIA implements IA {
    public void doIt() {
        System.out.println("doIt In BIA");
    }
}

CIA的内容如下:

package spi;

public class CIA implements IA {
    public void doIt() {
        System.out.println("doIt In CIA");
    }
}

Main的内容如下:
package spi;

import java.util.Iterator;
import java.util.ServiceLoader;

public class Main {
    public static void main(String[] args) {
        ServiceLoader spiLoader = ServiceLoader.load(IA.class);
        Iterator iaIterator = spiLoader.iterator();
        while (iaIterator.hasNext()) {
            iaIterator.next().doIt();
        }
    }
}
在META-INF/services/spi.IA文件中的内容如下:
spi.AIA
spi.BIA
spi.CIA

运行spi.Main,可以发现输出结果如下:

Java SPI机制_第2张图片

参考文献:

[1]http://singleant.iteye.com/blog/1497259

[2]http://blog.csdn.net/fenglibing/article/details/7083071

你可能感兴趣的:(语言)