com.github.azbh111.utils.java.spi.SPIUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils-java Show documentation
Show all versions of utils-java Show documentation
com.github.azbh111:utils-java
The newest version!
package com.github.azbh111.utils.java.spi;
import com.github.azbh111.utils.java.predicate.PredicateUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
/**
*
* @author pyz
* @date 2019/3/30 2:28 PM
*/
public class SPIUtils {
private static final String PREFIX = "META-INF/services/";
public static ServiceLoader load(Class service) {
return ServiceLoader.load(service, Thread.currentThread().getContextClassLoader());
}
public static ServiceLoader load(Class service, ClassLoader classLoader) {
return ServiceLoader.load(service, classLoader);
}
public static ServiceLoader loadInstalled(Class service) {
return ServiceLoader.loadInstalled(service);
}
/**
* 获取service的实现类
*
* @param service
* @param
* @return
*/
public static List> loadClass(Class service) {
return loadClass(service, Thread.currentThread().getContextClassLoader());
}
/**
* 获取service的实现类
*
* @param service
* @param
* @return
*/
public static List> loadClass(Class service, ClassLoader classLoader) {
try {
String fullName = PREFIX + service.getName();
Enumeration configs = null;
if (classLoader == null) {
configs = ClassLoader.getSystemResources(fullName);
} else {
configs = classLoader.getResources(fullName);
}
if (configs == null) {
return new ArrayList<>();
}
Predicate test = PredicateUtils.distinctBy(Function.identity());
List services = new ArrayList<>();
while (configs.hasMoreElements()) {
URL url = configs.nextElement();
for (String s : parse(service, url)) {
if (test.test(s)) {
services.add(s);
}
}
}
List> classes = new ArrayList<>(services.size());
Class c = null;
for (String s : services) {
try {
c = Class.forName(s, true, classLoader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + s + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + s + " not a subtype");
}
classes.add(c);
}
return classes;
} catch (IOException x) {
throw new ServiceConfigurationError(service.getName() + ": Error locating configuration files", x);
}
}
private static List parse(Class> service, URL u)
throws ServiceConfigurationError, IOException {
List names = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(u.openStream(), StandardCharsets.UTF_8))) {
int lc = 1;
while ((lc = parseLine(service, u, reader, lc, names)) >= 0) {
;
}
}
return names;
}
// Parse a single line from the given configuration file, adding the name
// on the line to the names list.
//
private static int parseLine(Class> service, URL u, BufferedReader r, int lc,
List names)
throws IOException, ServiceConfigurationError {
String ln = r.readLine();
if (ln == null) {
return -1;
}
int ci = ln.indexOf('#');
if (ci >= 0) {
ln = ln.substring(0, ci);
}
ln = ln.trim();
int n = ln.length();
if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) {
fail(service, u, lc, "Illegal configuration-file syntax");
}
int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp)) {
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
}
names.add(ln);
}
return lc + 1;
}
private static void fail(Class> service, String msg, Throwable cause)
throws ServiceConfigurationError {
throw new ServiceConfigurationError(service.getName() + ": " + msg,
cause);
}
private static void fail(Class> service, String msg)
throws ServiceConfigurationError {
throw new ServiceConfigurationError(service.getName() + ": " + msg);
}
private static void fail(Class> service, URL u, int line, String msg)
throws ServiceConfigurationError {
fail(service, u + ":" + line + ": " + msg);
}
}