您的位置:首页 > 编程语言 > Java开发

java SPI机制的初步学习

2017-04-14 00:00 701 查看
java SPI机制的初步学习

1. SPI机制

SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。简单的总结下java spi机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。 java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

2. SPI具体约定

java spi的具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader

入门实验:

tspi这个为接口包

alogger这个为ALogger实现tspi的实现包

blogger这个为BLogger实现tspi的实现包

tspiTest这个项目为测试包

把这4个做成4个单独的项目

(1) tspi项目(接口项目)

新建一个Logger的接口分别有debug,info,warn,error这4个方法。

package com.imddy.tspi;

public interface Logger {

public void debug(String logger);

public void info(String logger);

public void warn(String logger);

public void error(String logger);

}

在来个工具类LoggerFactory来获取Logger,(这里就使用了spi机制)

package com.imddy.tspi;

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

public class LoggerFactory {

public LoggerFactory() {

}

public static Logger getLogger() {

Logger logger = null;

ServiceLoader<Logger> serviceLoader = ServiceLoader.load(Logger.class);
Iterator<Logger> loggers = serviceLoader.iterator();
if (loggers.hasNext()) {
logger = loggers.next();
}

return logger;
}

}


这个项目到包成jar 由于没有什么依赖,pom.xml基本是默认内容。

(2)alogger项目(A实现项目)

这里有个ALogger为Logger的实现类:

package com.imddy.alogger;

import com.imddy.tspi.Logger;

public class ALogger implements Logger{

public ALogger() {

}

public void debug(String logger) {
System.out.println("ALogger-->debug: " + logger);
}

public void info(String logger) {
System.out.println("ALogger-->info: " + logger);
}

public void warn(String logger) {
System.out.println("ALogger-->warn: " + logger);
}

public void error(String logger) {
System.out.println("ALogger-->error: " + logger);
}

}

在资源目录下创建 ”META-INF/Services目录” 在这个目录下,新建一个为 “com.imddy.tspi.Logger” 的文件(接口全限定名称),其内容为 “com.imddy.alogger.ALogger” (实现类全限定名称)

pom.xml中需要依赖接口项目,这个项目也是打包成一个jar包。



(3)blogger项目(B实现项目)

这里有个BLogger为Logger的实现类:

package com.imddy.blogger;

import com.imddy.tspi.Logger;

public class BLogger implements Logger{

public BLogger() {

}

public void debug(String logger) {
System.out.println("BLogger-->debug: " + logger);
}

public void info(String logger) {
System.out.println("BLogger-->info: " + logger);
}

public void warn(String logger) {
System.out.println("BLogger-->warn: " + logger);
}

public void error(String logger) {
System.out.println("BLogger-->error: " + logger);
}

}

在资源目录下创建 ”META-INF/Services目录” 在这个目录下,新建一个为 “com.imddy.tspi.Logger” 的文件(接口全限定名称),其内容为 “com.imddy.blogger.BLogger” (实现类全限定名称)

pom.xml中需要依赖接口项目,这个项目也是打包成一个jar包。



(4)tspiTest项目 (测试项目)

pom.xml中的依赖添加:

<dependency>
<groupId>com.imddy</groupId>
<artifactId>tspi</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- <dependency>
<groupId>com.imddy</groupId>
<artifactId>alogger</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> -->
<dependency>
<groupId>com.imddy</groupId>
<artifactId>blogger</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

写代码只需要接口项目依赖,运行是有pathclass有A实现就使用A实现,有B实现就使用B实现。

测试代码如下:

package com.imddy.tspiTest;

import com.imddy.tspi.Logger;
import com.imddy.tspi.LoggerFactory;

public class App {

private static Logger logger = LoggerFactory.getLogger();

public static void main(String[] args) {

logger.debug("this is use debug... ");

logger.info("this is use info... ");

logger.warn("this is use warn... ");

logger.error("this is use error... ");

}
}


运行效果如图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: