java spi的具体约定如下 :
当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。
pom.xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
项目结构
system.properties,test.properties
接口ISysConfig
package com.ghg.spi.service;
import java.util.Map;
public interface ISysConfig {
/**
* 加载所有配置参数
*
* @throws BusinessException
*/
void loadConfig() throws Exception;
/**
* 取得所有配置参数
*
* @return
*/
Map<String,Object> getAllParams();
/**
* 根据参数名取得参数值
*
* @param paramKey 配置参数名
* @return
*/
Object getParam(String paramKey);
}
声明
工具类
package com.ghg.spi.helper;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
public class PropertiesHelper {
private final Properties properties = new Properties();
/**
* windows系统文件路径分隔符
*/
public static final char WIN_SEPARATOR = '\\';
/**
* unix系统文件路径分隔符
*/
public static final char UNIX_SEPARATOR = '/';
public PropertiesHelper(String... resourcesPaths) throws IOException {
loadProperties(resourcesPaths);
}
public Properties getProperties() {
return properties;
}
private void loadProperties(String... resourcesPaths) throws IOException {
for (String location : resourcesPaths) {
if (StringUtils.isNotEmpty(location)) {
// 修正下路径,classLoader不以/开头
if (location.charAt(0) == UNIX_SEPARATOR) {
location = location.substring(1);
}
try (InputStream in = readFileFromClassPath(location)) {
if (in != null) {
properties.load(in);
}
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
}
}
/**
* 读取资源文件
* @Title: readFileFromClassPath
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @param filePath
* @param @return 设定文件
* @return InputStream 返回类型
* @throws
*/
protected InputStream readFileFromClassPath(String filePath) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = PropertiesHelper.class.getClassLoader();
}
if (filePath.charAt(0) == UNIX_SEPARATOR) {
filePath = filePath.substring(1);
}
return classLoader.getResourceAsStream(filePath);
}
}
实现
package com.ghg.spi.imp;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang3.ArrayUtils;
import com.ghg.spi.helper.PropertiesHelper;
import com.ghg.spi.service.ISysConfig;
public class BaseSysConfig implements ISysConfig {
private String[] propertiesFiles;
private static final Map<String,Object> paramMap = new HashMap<>();
private static AtomicBoolean isLoaded = new AtomicBoolean(false);
public BaseSysConfig() throws Exception {
// propertiesFiles = new String[]{ "system.properties" };
this("system.properties","test.properties");
}
/**
* 构造函数,指定配置文件
*
* @param configFiles
* @throws Exception
*/
public BaseSysConfig(String... configFiles) throws Exception {
propertiesFiles = configFiles;
loadConfig();
}
/**
* 加载配置文件
*/
public synchronized void loadConfig() throws Exception {
/**
* 判断是否已经加载
*/
if(!isLoaded.get()) {
try {
loadFromConfigFile();
} catch (Exception e) {
throw new Exception();
}
}
isLoaded.set(true);
}
/**
* @throws IOException
* 加载
* @Title: loadFromConfigFile
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param 设定文件
* @return void 返回类型
* @throws
*/
protected void loadFromConfigFile() throws IOException {
if(ArrayUtils.isNotEmpty(propertiesFiles)) {
PropertiesHelper propertiesHelper = new PropertiesHelper(propertiesFiles);
Properties properties = propertiesHelper.getProperties();
if(properties!=null&& !properties.isEmpty()) {
for(Entry<Object,Object> prop:properties.entrySet()) {
paramMap.put(String.valueOf(prop.getKey()), prop.getValue());
}
}else {
System.out.println("未设置参数配置文件");
}
}
}
public Map<String,Object> getAllParams() {
return paramMap;
}
public Object getParam(String paramKey) {
return paramMap.get(paramKey);
}
}
测试
package com.ghg.spi.test;
import com.ghg.spi.imp.BaseSysConfig;
public class Test1 {
public static void main(String[] args) throws Exception {
BaseSysConfig baseSysConfig = new BaseSysConfig();
System.out.println(baseSysConfig.getAllParams());
System.out.println(baseSysConfig.getParam("debugMode"));
}
}
加载
public class Test2 {
public static void main(String[] args) {
ServiceLoader<ISysConfig> serviceLoader = ServiceLoader.load(ISysConfig.class);
System.out.println(serviceLoader.toString());
Iterator<ISysConfig> iterator = serviceLoader.iterator();
System.out.println(iterator.next().getAllParams());
}
}