SPI META-INF/services/目录

package com.thfund.wuyy.test;

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

import com.thfund.wuyy.intf.CacheDataSource;

public class CMain {

	public static void main (String[] args){
		
		ServiceLoader s = ServiceLoader.load(CacheDataSource.class);
		Iteratorit = s.iterator();
		for (;it.hasNext();){
			CacheDataSource cacheDataSource = it.next();
			cacheDataSource.getDataSource();
		}
	}
}

上面是主线程的源码:

package com.thfund.wuyy.intf;

public interface CacheDataSource {

	String getDataSource();
}

此为SPI接口源码:

package com.thfund.wuyy.impl;

import com.thfund.wuyy.intf.CacheDataSource;

public class MemoryCacheDataSource implements CacheDataSource {

	@Override
	public String getDataSource() {
		// TODO Auto-generated method stub
		System.out.println(this.getClass().getClassLoader());
		System.out.println("MemoryCacheDataSource");
		return null;
	}

}

这是具体实现类的源码:

 

SPI META-INF/services/目录_第1张图片

整个项目的目录结构:

com.thfund.wuyy.intf.CacheDataSource 文件的内容:com.thfund.wuyy.impl.MemoryCacheDataSource

 

编译命令:

javac -d bin src/com/thfund/wuyy/impl/*.java src/com/thfund/wuyy/intf/*.java src/com/thfund/wuyy/test/*.java

此处对比C++,C++用makfile编译需要自己编写每个文件之前的依赖关系,但明显javac 不用。这时非常方便的!

运行命令:

java.exe -Dfile.encoding=UTF-8 -classpath D:\workspace\Program\practice\selftest\SPITest\bin com.thfund.wuyy.test.CMain

 

第一个细节点(极其简单高手勿喷):

用编译命令编译完项目目录结构如下:

D:\workspace\Program\practice\selftest\SPITest>javac -d bin src/com/thfund/wuyy/impl/*.java src/com/thfund/wuyy/intf/*.java src/com/thfund/wuyy/test/*.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

D:\workspace\Program\practice\selftest\SPITest>dir bin
 Volume in drive D is DATA
 Volume Serial Number is 526A-FE14

 Directory of D:\workspace\Program\practice\selftest\SPITest\bin

2018/11/21  16:47              .
2018/11/21  16:47              ..
2018/11/21  16:29              com
               0 File(s)              0 bytes
               3 Dir(s)  233,028,145,152 bytes free

D:\workspace\Program\practice\selftest\SPITest>

此时我们在META-INF/services 目录创建的文件还没有拷过来需要用命令拷贝一下,如果用eclipse 编译器,eclipse 会将src目录下所有的目录都拷贝到bin目录下。

下面我们来看一下ServiceLoader.load 是怎么找到配置文件并通过配置文件中的类名加载类、执行。

首先看一下ServiceLoader类的一点代码

public final class ServiceLoader
    implements Iterable
{

    private static final String PREFIX = "META-INF/services/";

    // The class or interface representing the service being loaded
    private Class service;
    
    /* 

    此处省略一万行
    */
}

我们看到ServiceLoader类写死了META-INF 目录,再来看一下我们的执行命令:

java.exe -Dfile.encoding=UTF-8 -classpath D:\workspace\Program\practice\selftest\SPITest\bin com.thfund.wuyy.test.CMain

ServiceLoader类会扫描所有classpath 目录中的META-INF/services/ 然后查找com.thfund.wuyy.intf.CacheDataSource文件中的类名称,然后创建。

加载函数如下:

public static  ServiceLoader load(Class service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

 

你可能感兴趣的:(java基础)