/**
* Load files under SERVICE_DIRECTORY.
*/
private void loadDirectory(final Map> classes) {
String fileName = SERVICE_DIRECTORY + clazz.getName();
try {
ClassLoader classLoader = ExtensionLoader.class.getClassLoader();
Enumeration urls = classLoader != null ? classLoader.getResources(fileName)
: ClassLoader.getSystemResources(fileName);
if (urls != null) {
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
loadResources(classes, url);
}
}
} catch (IOException t) {
log.error("load extension class error {}", fileName, t);
}
}private void loadResources(final Map> classes, final URL url) throws IOException {
try (InputStream inputStream = url.openStream()) {
Properties properties = new Properties();
properties.load(inputStream);
properties.forEach((k, v) -> {
String name = (String) k;
String classPath = (String) v;
if (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(classPath)) {
try {
loadClass(classes, name, classPath);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("load extension resources error", e);
}
}
});
} catch (IOException e) {
throw new IllegalStateException("load extension resources error", e);
}
}private void loadClass(final Map> classes,
final String name, final String classPath) throws ClassNotFoundException {
Class> subClass = Class.forName(classPath);
if (!clazz.isAssignableFrom(subClass)) {
throw new IllegalStateException("load extension resources error," + subClass + " subtype is not of " + clazz);
}
Activate annotation = subClass.getAnnotation(Activate.class);
if (annotation == null) {
throw new IllegalStateException("load extension resources error," + subClass + " with Activate annotation");
}
Class> oldClass = classes.get(name);
if (oldClass == null) {
classes.put(name, subClass);
} else if (oldClass != subClass) {
throw new IllegalStateException("load extension resources error,Duplicate class " + clazz.getName() + " name " + name + " on " + oldClass.getName() + " or " + subClass.getName());
}
}
5、根据key,去缓存查找相应的类实例
public T getActivate(final String name) {
if (StringUtils.isBlank(name)) {
throw new NullPointerException("get Activate name is null");
}
Holder
核心代码
@Slf4j
@SuppressWarnings("all")
public final class ExtensionLoader {private static final String SERVICE_DIRECTORY = "META-INF/services/";
private static final Map, ExtensionLoader>> LOADERS = new ConcurrentHashMap<>();
private final Class clazz;
private final Holder
使用示例
1、定义服务接口
@SPI("mysql")
public interface SqlDialect {String dialect();
}
2、定义具体实现类
@Activate
public class MysqlDialect implements SqlDialect {
@Override
public String dialect() {
return "mysql";
}}
@Activate
public class OracleDialect implements SqlDialect {
@Override
public String dialect() {
return "oracle";
}}