Java ServiceLoader(SPI)学习
2016-07-16 20:49
375 查看
1.几个不错的关于ServiceLoader的文章,大家可以先参考一下
1) http://www.myexception.cn/program/1355384.html 这篇的后面的问题分析不错2) http://singleant.iteye.com/blog/1497259
2.实例代码
直接上代码吧1)接口
[java] view
plain copy
package com.unei.serviceloader;
/**
* Created by sun on 2015/7/25.
*/
public interface Command {
public void execute();
}
2)实现类
[java] view
plain copy
package com.unei.serviceloader;
/**
* Created by sun on 2015/7/25.
*/
public class ShutdownCommand implements Command{
public void execute() {
System.out.println("shutdown....");
}
}
[java] view
plain copy
package com.unei.serviceloader;
/**
* Created by sun on 2015/7/25.
*/
public class StartCommand implements Command{
public void execute() {
System.out.println("start....");
}
}
3)配置文件
由于是使用maven构建的项目,所以就在resources下面新建目录META-INF/services,在该目录下新建文件com.unei.serviceloader.Command,即完整的接口名
文件内容如下:
[plain] view
plain copy
com.unei.serviceloader.ShutdownCommand
com.unei.serviceloader.StartCommand
4)main方法
[java] view
plain copy
package com.unei.serviceloader;
import java.util.ServiceLoader;
/**
* Created by sun on 2015/7/25.
*/
public class Main {
public static void main(String[] args) {
ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class);
for(Command command:serviceLoader){
command.execute();
}
}
}
5)编译执行
[plain] view
plain copy
mvn clean install -Dmaven.test.skip=true
mvn exec:java -Dexec.mainClass=com.unei.serviceloader.Main
3.activemq中的使用实例
第一次接触到ServiceLoader就是在activemq的启动过程中,所以学习了一下
activemq broker启动时,调用的是org.apache.activemq.console.command.ShellCommand类,ShellCommand.main调用runTask,runTask会调用getCommands方法,下面看一下getCommands的代码:
[java] view
plain copy
ArrayList<Command> getCommands() {
ServiceLoader<Command> loader = ServiceLoader.load(Command.class);
Iterator<Command> iterator = loader.iterator();
ArrayList<Command> rc = new ArrayList<Command>();
boolean done = false;
while (!done) {
try {
if( iterator.hasNext() ) {
rc.add(iterator.next());
} else {
done = true;
}
} catch (ServiceConfigurationError e) {
// it's ok, some commands may not load if their dependencies
// are not available.
}
}
return rc;
}
ServiceLoader会读取META-INF/services/org.apache.activemq.console.command.Command 配置的类并在迭代时将其实例化。
回头看一下runTask方法:
[java] view
plain copy
protected void runTask(List<String> tokens) throws Exception {
// Process task token
if (tokens.size() > 0) {
Command command=null;
String taskToken = (String)tokens.remove(0);
for( Command c: getCommands() ) {
if( taskToken.equals(c.getName()) ) {
command = c;
break;
}
}
if( command == null ) {
if (taskToken.equals("help")) {
printHelp();
} else {
printHelp();
}
}
if( command!=null ) {
command.setCommandContext(context);
command.execute(tokens);
}
} else {
printHelp();
}
}
该方法根据类名选择Command,并执行。
问题:
1.配置文件为什么要放在META-INF/services下面?ServiceLoader.PREFIX定义如下:
private static final String PREFIX = "META-INF/services/";
JDK已经写死了。
但是如果ServiceLoader在load时提供Classloader,则可以从其他的目录读取。
2.ServiceLoader读取实现类是什么时候实例化的?
ServiceLoader.LazyIterator.nextService中实例化,即load的结果迭代时才会被实例化。
相关文章推荐
- 基于Linux内核SPI子系统工作机制
- eMMC的MMC模式与SPI模式
- SPI总线协议
- SPI总线规范
- SPI vs IIC
- motan源码解读之--SPI(Service Provider Interface)实现方式浅析
- STM32 SPI工作在主模式时用DMA方式接收数据
- java spi
- TMS320F28335学习SPI模块总结笔记
- SPI总线协议及SPI时序图详解
- openfire与agsxmpp、qxmpp、psi等非spark的xmpp客户端通信
- stm32f072的spi的设置注意事项。
- MSP430 SPI硬件接口
- 安卓应用开发用户体验之禁止EditText自动获取焦点
- Java的SPI机制介绍
- SPI协议简介
- SPI
- STM32F411的DMA使用注意清除标志位
- SPI写入数据的时候记得读取,不然会一直读出0xFF!