All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zusmart.basic.extension.ExtensionLoader Maven / Gradle / Ivy
package com.zusmart.basic.extension;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.zusmart.basic.logging.Logger;
import com.zusmart.basic.logging.LoggerFactory;
import com.zusmart.basic.toolkit.AnnotationUtils;
import com.zusmart.basic.toolkit.ClassUtils;
import com.zusmart.basic.toolkit.GenericUtils;
import com.zusmart.basic.toolkit.StringUtils;
/**
* 参考Dubbo实现的SPI机制,部分代码进行调整
*
* @author Administrator
*
* @param
* 扩展点接口对象
*/
public class ExtensionLoader {
private static final String PATH_SERVICES = "META-INF/services/";
private static final String PATH_INTERNAL = "META-INF/internal/";
private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
private static final ConcurrentMap, ExtensionLoader>> LOADERS = new ConcurrentHashMap, ExtensionLoader>>();
private static class Holder {
private volatile H value;
private H get() {
return this.value;
}
private void set(H value) {
this.value = value;
}
}
private static ClassLoader getClassLoader() {
return ClassUtils.getClassLoader(ExtensionLoader.class);
}
private static void assertExtension(Class> type) {
if (null == type) {
throw new IllegalArgumentException("extension type must not be null");
}
if (!type.isInterface()) {
throw new IllegalArgumentException(String.format("extension type is not interface (%s)", type));
}
if (!AnnotationUtils.hasAnnotation(type, Extension.class)) {
throw new IllegalArgumentException(String.format("extension type missing @Extension annotation (%s)", type));
}
}
public static ExtensionLoader getExtensionLoader(Class type) {
assertExtension(type);
ExtensionLoader loader = GenericUtils.parse(LOADERS.get(type));
if (null == loader) {
LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = GenericUtils.parse(LOADERS.get(type));
}
return loader;
}
public static E getExtension(Class type, String name) {
ExtensionLoader loader = getExtensionLoader(type);
return loader.getExtension(name);
}
public static E getDefaultExtension(Class type) {
ExtensionLoader loader = getExtensionLoader(type);
return loader.getDefaultExtension();
}
private final String name;
private final Class> type;
private final ExtensionScope scope;
private final Holder>> cacheClasses = new Holder>>();
private final ConcurrentMap> cachedData = new ConcurrentHashMap>();
private ExtensionLoader(Class> type) {
assertExtension(type);
Extension extension = type.getAnnotation(Extension.class);
this.name = extension.value();
this.type = type;
this.scope = extension.scope();
}
/**
* 获取指定名称的扩展点对象
*
* @param name
* 扩展点名称
* @return 扩展点对象
*/
public T getExtension(String name) {
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("extension name must not be blank");
}
Holder holder = this.cachedData.get(name);
if (null == holder) {
this.cachedData.putIfAbsent(name, new Holder());
holder = this.cachedData.get(name);
}
if (this.scope == ExtensionScope.Singleton) {
Object instance = holder.get();
if (null == instance) {
synchronized (holder) {
instance = holder.get();
if (null == instance) {
instance = this.createExtension(name);
holder.set(instance);
}
}
}
return GenericUtils.parse(instance);
} else {
return GenericUtils.parse(this.createExtension(name));
}
}
/**
* 获取默认名称的扩展点对象,可能为空
*
* @return 扩展点对象
*/
public T getDefaultExtension() {
if (StringUtils.isBlank(this.name)) {
return null;
}
return this.getExtension(this.name);
}
private Object createExtension(String name) {
Class> clazz = this.getExtensionClasses().get(name);
if (null == clazz) {
throw new IllegalStateException(String.format("can not find extension (interface : %s , name : %s)", this.type, name));
}
try {
T instance = GenericUtils.parse(clazz.newInstance());
this.injectExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException(String.format("create instance failed (interface : %s ,name : %s , class : %s)", this.type, name, clazz));
}
}
private void injectExtension(Object instance) {
}
private Map> getExtensionClasses() {
Map> classes = this.cacheClasses.get();
if (null == classes) {
synchronized (this.cacheClasses) {
classes = this.cacheClasses.get();
if (null == classes) {
classes = this.loadExtensionClasses();
this.cacheClasses.set(classes);
}
}
}
return classes;
}
private Map> loadExtensionClasses() {
Map> classes = new HashMap>();
this.loadDirectory(classes, PATH_SERVICES);
this.loadDirectory(classes, PATH_INTERNAL);
return classes;
}
private void loadDirectory(Map> classes, String path) {
String fileName = path + this.type.getName();
try {
Enumeration urls = null;
ClassLoader classLoader = getClassLoader();
if (null != classLoader) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (null != urls) {
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
this.loadResource(classes, classLoader, url);
}
}
} catch (Throwable t) {
logger.error("load extension class failed (interface : {} , file : {})", this.type, fileName, t);
}
}
private void loadResource(Map> classes, ClassLoader classLoader, URL url) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
try {
String line = null;
while ((line = reader.readLine()) != null) {
final int ci = line.indexOf("#");
if (ci >= 0) {
line = line.substring(0, ci);
}
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
int i = line.indexOf("=");
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
} else {
name = line;
}
Class> clazz = Class.forName(line);
if (clazz.isAnnotationPresent(ExtensionService.class)) {
ExtensionService service = clazz.getAnnotation(ExtensionService.class);
if (StringUtils.isNotBlank(service.value())) {
name = service.value();
}
}
classes.put(name, Class.forName(line));
logger.debug("load extension class success (interface : {} , path : {} , line : {} , name : {})", this.type, url, line, name);
} catch (Throwable tt) {
logger.error("load extension class failed (interface : {} , path : {} , line : {})", this.type, url, line, tt);
}
}
}
} finally {
reader.close();
}
} catch (Throwable t) {
logger.error("load extension class failed (interface : {} , path : {})", this.type, url, t);
}
}
}