概述
public class ExtensionLoader{private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);private ConcurrentMap singletonInstances = null;//存放所有扩展点类的集合,key是扩展名,每一个扩展文件中可以定义多个扩展类
private ConcurrentMap> extensionClasses = null;//加载该路径下所有扩展类
private static final String SPI_LOCATION = "META-INF/services/";privateClassLoader classLoader;private Classtype;private volatile boolean init = false;//存储扩展点对象和其对应的扩展加载器
private static final Map, ExtensionLoader>> extensionLoaders = new ConcurrentHashMap<>();//通过构造方法设置类加载器,使用Thread.currentThread().getContextClassLoader(),如果没有setContextClassLoader()则为系统类加载器AppClassLoader
private ExtensionLoader(Classtype) {this(type, Thread.currentThread().getContextClassLoader());
}private ExtensionLoader(Classtype, ClassLoader classLoader) {this.type =type;this.classLoader =classLoader;
}
@SuppressWarnings("unchecked")public static ExtensionLoader getExtensionLoader(Classtype) {//根据扩展点类型获取对应的扩展加载器
ExtensionLoader loader = (ExtensionLoader) extensionLoaders.get(type);if (loader == null) {//如果没有该扩展加载器,则进行初始化
loader =initExtensionLoader(type);
}returnloader;
}//初始化方法是静态的且加了锁,相当于在类对象上加锁,可以保证同时只有一个扩展器的初始化操作
@SuppressWarnings("unchecked")private static synchronized ExtensionLoader initExtensionLoader(Classtype) {
ExtensionLoader loader = (ExtensionLoader) extensionLoaders.get(type);if (loader == null) {
loader= new ExtensionLoader<>(type);
extensionLoaders.putIfAbsent(type, loader);
loader= (ExtensionLoader) extensionLoaders.get(type);
}returnloader;
}
@SuppressWarnings("unchecked")public ListgetExtensions() {
checkAndInit();
List extensions = new ArrayList<>(extensionClasses.size());for (Map.Entry>entry : extensionClasses.entrySet()) {
extensions.add(getExtension(entry.getKey()));
}
extensions.sort(new ExtensionOrderComparator());returnextensions;
}//根据扩展名获取扩展点对象
publicT getExtension(String name) {
checkAndInit();if (name == null) {return null;
}try{//注意,@Spi是使用在扩展点接口上的,@SpiMeta是使用在实现类上的
Spi spi = type.getAnnotation(Spi.class);//单例类型
if (spi.scope() ==Scope.SINGLETON) {returngetSingletonInstance(name);
}else{//原型类型
Class clz =extensionClasses.get(name);if (clz == null) {return null;
}returnclz.newInstance();
}
}catch(Exception e) {new RuntimeException(type.getName() + ":Error when getExtension " +name, e);
}return null;
}
@SuppressWarnings("unchecked")private T getSingletonInstance(String name) throwsInstantiationException, IllegalAccessException {
T obj=singletonInstances.get(name);if (obj != null) {returnobj;
}
Class clz =extensionClasses.get(name);if (clz == null) {return null;
}//加锁对象为集合对象,确保只有一个线程能创建扩展点对象
synchronized(singletonInstances) {
obj=singletonInstances.get(name);if (obj != null) {returnobj;
}
obj=clz.newInstance();
singletonInstances.put(name, obj);
}returnobj;
}private voidcheckAndInit() {//init被volatile修饰,确保只有一个线程进行初始化
if (!init) {
loadExtensionClasses();
}
}//这里在方法级别加锁,锁对象是扩展点对应的扩展类加载器对象
private synchronized voidloadExtensionClasses() {if(init) {return;
}//将META-INF/services/目录下的扩展点加载进集合中
extensionClasses =loadExtensionClasses(SPI_LOCATION);
singletonInstances= new ConcurrentHashMap<>();
init= true;
}private ConcurrentMap>loadExtensionClasses(String prefix) {//根据前缀和类的全限定名来读取文件,所以这里注意扩展点的文件名称必须是类的全限定名
String fullName = prefix +type.getName();
List classNames = new ArrayList();try{
Enumerationurls;if (classLoader == null) {
urls=ClassLoader.getSystemResources(fullName);
}else{
urls=classLoader.getResources(fullName);
}if (urls == null || !urls.hasMoreElements()) {return new ConcurrentHashMap<>();
}while(urls.hasMoreElements()) {
URL url=urls.nextElement();//解析类
parseUrl(type, url, classNames);
}
}catch(Exception e) {throw new RuntimeException("ExtensionLoader loadExtensionClasses error, prefix: " + prefix + " type: " +type.getClass(), e);
}//将类加载进内存,并放入集合中
returnloadClass(classNames);
}
@SuppressWarnings("unchecked")private ConcurrentMap> loadClass(ListclassNames) {
ConcurrentMap> map = new ConcurrentHashMap>();for(String className : classNames) {try{
Classclz;if (classLoader == null) {//classLoader为空,使用加载当前类的类加载器进行加载
clz = (Class) Class.forName(className);
}else{
clz= (Class) Class.forName(className, true, classLoader);
}
checkExtensionType(clz);
String spiName=getSpiName(clz);if(map.containsKey(spiName)) {new RuntimeException(clz.getName() + ":Error spiName already exist " +spiName);
}else{
map.put(spiName, clz);
}
}catch(Exception e) {
logger.error(type.getName()+ ":" + "Error load spi class", e);
}
}returnmap;
}private void checkExtensionType(Classclz) {
checkClassPublic(clz);
checkConstructorPublic(clz);
checkClassInherit(clz);
}private void checkClassPublic(Classclz) {if (!Modifier.isPublic(clz.getModifiers())) {new RuntimeException(clz.getName() + ":Error is not a public class");
}
}private void checkClassInherit(Classclz) {if (!type.isAssignableFrom(clz)) {new RuntimeException(clz.getName() + ":Error is not instanceof " +type.getName());
}
}private void checkConstructorPublic(Classclz) {
Constructor>[] constructors =clz.getConstructors();if (constructors == null || constructors.length == 0) {new RuntimeException(clz.getName() + ":Error has no public no-args constructor");
}for (Constructor>constructor : constructors) {if (Modifier.isPublic(constructor.getModifiers()) && constructor.getParameterTypes().length == 0) {return;
}
}new RuntimeException(clz.getName() + ":Error has no public no-args constructor");
}public String getSpiName(Class>clz) {
SpiMeta spiMeta= clz.getAnnotation(SpiMeta.class);//如果SpiMeta中没有定义name属性,则使用类型,如@SpiMeta(name = "coreSamplePrinter")
return (spiMeta != null && !"".equals(spiMeta.name())) ?spiMeta.name() : clz.getSimpleName();
}private void parseUrl(Class type, URL url, List classNames) throwsServiceConfigurationError {
InputStream inputStream= null;
BufferedReader reader= null;try{
inputStream=url.openStream();
reader= new BufferedReader(newInputStreamReader(inputStream, StandardCharsets.UTF_8));
String line;int indexNumber = 0;while ((line = reader.readLine()) != null) {
indexNumber++;
parseLine(type, url, line, indexNumber, classNames);
}
}catch(Exception x) {
logger.error(type.getName()+ ":" + "Error reading spi configuration file", x);
}finally{try{if (reader != null) {
reader.close();
}if (inputStream != null) {
inputStream.close();
}
}catch(IOException y) {
logger.error(type.getName()+ ":" + "Error closing spi configuration file", y);
}
}
}private void parseLine(Class type, URL url, String line, int lineNumber, List names) throwsIOException,
ServiceConfigurationError {int ci = line.indexOf('#'); //可以使用#在扩展文件后写一些说明
if (ci >= 0) {
line= line.substring(0, ci);
}
line=line.trim();if (line.length() <= 0) {return;
}if ((line.indexOf(' ') >= 0) || (line.indexOf('t') >= 0)) {throw new RuntimeException(type.getName() + ": " + "Illegal spi configuration-file syntax");
}int cp = line.codePointAt(0);if (!Character.isJavaIdentifierStart(cp)) {throw new RuntimeException(type.getName() + ": " + url + ": " + line + ": " + "Illegal spi provider-class name: " +line);
}for (int i = Character.charCount(cp); i < line.length(); i +=Character.charCount(cp)) {
cp=line.codePointAt(i);if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {throw new RuntimeException(type.getName() + ": " + url + ": " + line + ": " + "Illegal spi provider-class name: " +line);
}
}if (!names.contains(line)) {
names.add(line);
}
}
}
最后
以上就是顺心店员为你收集整理的java spi 扩展_SPI扩展机制在框架中的使用的全部内容,希望文章能够帮你解决java spi 扩展_SPI扩展机制在框架中的使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复