类加载失败:找不到类加载器

2023/01/11 java

我们有一个类加载方式,能通过SPI机制加载类,但类加载失败了


[TOC]

背景

InfoCenter简述

InfoCenter 是一个依赖 qmq、qconfig,基于本地缓存实现公共配置数据查询服务的Jar包,由一个配置加载模块与多个配置插件组成,能让万量级配置数据的变更于多个业务系统间秒级生效。

以汇率数据配置为例,当汇率数据配置发生变更或业务系统启动时,配置加载模块通过HTTP请求从服务端加载全量汇率数据配置,然后由汇率配置插件解析并保存在本地内存中。业务系统通过调用汇率配置插件的静态方法来快速获取汇率配置。

InfoCenter 有一个懒加载机制,即只有业务系统用到汇率数据配置时才会加载汇率配置插件类。或在业务系统启动时通过白名单配置、历史访问记录等方式提前加载该类。

配置插件的默认实现类通过自定义的SPI集成于 META-INF/spi 目录下,以实现解耦:业务系统可自定义配置插件

InfoCenter 的SPI实现 参考了 Dubbo 的SPI实现,不同于Java的 ServiceLoader 会遍历SPI配置并实例化所有实现类,InfoCenter和Dubbo的ServiceLoader都可以”按需加载“,从而实现懒加载。

Java的SPI实现参考:Introduction to the Service Provider Interfaces

Dubbo的SPI实现参考:Dubbo SPI

问题描述

某业务系统通过 InfoCenter 查询汇率失败,报错为Jar包中的汇率配置插件类加载失败,异常栈如下:

java.lang.IllegalStateException: No such service com.qunar.flight.qbd.client.rate.logic.IRateLogic by name default
        at com.qunar.flight.qbd.framework.kernel.extension.ServiceLoader.findServiceClassLoadException(ServiceLoader.java:368)
        at com.qunar.flight.qbd.framework.kernel.extension.ServiceLoader.getServiceClass(ServiceLoader.java:340)
        at com.qunar.flight.qbd.framework.kernel.extension.ServiceLoader.get(ServiceLoader.java:464)
        at com.qunar.flight.qbd.framework.kernel.extension.ServiceLoader.getDefault(ServiceLoader.java:298)
        at com.qunar.flight.qbd.client.rate.RateBeanFactory.getRateLogic(RateBeanFactory.java:79)
        at com.qunar.flight.qbd.client.unified.facade.QbdRateFacades.getGdsRate(QbdRateFacades.java:99)
        at com.qunar.flight.userproduct.athena.house.core.i18n.service.impl.PriceTranslateServiceImpl.translate(PriceTranslateServiceImpl.java:43)
        at com.qunar.flight.userproduct.athena.house.core.i18n.service.impl.replace.strategy.AbstractReplaceStrategy.doReplace(AbstractReplaceStrategy.java:37)
        at com.qunar.flight.userproduct.athena.house.core.i18n.service.impl.replace.strategy.DynamicJoinReplaceStrategy.replace(DynamicJoinReplaceStrategy.java:38)
        at com.qunar.flight.userproduct.athena.house.core.i18n.service.impl.I18nTranslateServiceImpl.getReplacedVal(I18nTranslateServiceImpl.java:292)
        at com.qunar.flight.userproduct.athena.house.core.i18n.service.impl.I18nTranslateServiceImpl.replace(I18nTranslateServiceImpl.java:280)
        at com.qunar.flight.userproduct.athena.house.core.i18n.service.impl.I18nTranslateServiceImpl.lambda$parseJsonPath$0(I18nTranslateServiceImpl.java:145)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
        at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
        at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

疑问点

多次验证该问题后,我们整理了以下两个疑问点:

疑问1:其它业务系统、配置插件无法复现此问题

InfoCenter 由一个配置加载模块与多个配置插件组成,所有的配置插件都共用一个配置加载模块

多次测试其它业务系统、其它配置插件,均无法复现此问题。

疑问2:该业务系统该问题不稳定复现

在该业务系统上进行debug测试:

  • 断点阻塞时间较短的情况下,该问题大概率复现。
  • 断点阻塞时间较长的情况下,该问题大概率无法复现。

疑问3:出现此问题后,重试也无法重新加载类

debug复现

第一次加载汇率配置类时,判断汇率配置接口的 ServersLoader 实例中nameMapping为空,初始化加载所有实现类。

image-20230214105502634

在获取汇率配置接口的默认实现类时,发现getServiceClasses()方法并没有加载该配置接口的所有实现类,包括默认实现类。

导致抛出类加载失败异常。

image-20230112212905585

如下图所示,当前线程的上下文类加载器为null

image-20230214194829493

如下图所示,当前线程的线程池为ForkJoinPool,其中的contextClassLoadernull

image-20230214195159434

正常情况下,我们拿到的类加载器是 org.apache.catalina.loader.ParallelWebappClassLoader,如下图所示:

业务代码分析

业务代码调用类加载逻辑的上游,有stream的parallel用法,如下图所示:

类加载代码分析

业务系统通过下列静态方法获取汇率配置。

此方法先加载汇率配置类,再从该类中获取汇率配置。

	public static ExchangeRateVO getGdsRate(String sourceCurrency, String targetCurrency) {
		try {
			return RateBeanFactory.getRateLogic().getGdsRate(sourceCurrency, targetCurrency);
		} catch (Exception e) {
			QMonitor.recordOne("qbd_QbdRateFacades_getGdsRate_error");
			throw e;
		}
	}

业务系统通过下列方法获取汇率配置类。

如果该类为空,通过自定义 ServiceLoader 实现加载配置接口的实现类。

	private static IRateLogic rateLogic;

	public static IRateLogic getRateLogic() {
		if (rateLogic == null) {
			rateLogic = ServiceLoader.load(IRateLogic.class).getDefault();
		}
		return rateLogic;
	}

业务系统通过下列load()工厂方法加载 ServiceLoader 实例。

自定义 ServiceLoader 中维护了一个 SERVICE_LOADERS map,每个配置接口都有对应的 ServiceLoader 实例。

当某个接口没有 ServiceLoader 实例时,会在map中新增一个 new ServiceLoader<>(type)

	private static final ConcurrentMap<Class<?>, ServiceLoader<?>> SERVICE_LOADERS = new ConcurrentHashMap<>();
	
	/**
	 * {@link ServiceLoader}的工厂方法。
	 *
	 * @param type 扩展点接口类型
	 * @param <T>  扩展点类型
	 * @return {@link ServiceLoader}实例
	 * @throws IllegalArgumentException 参数为<code>null</code>;或是扩展点接口上没有{@link SPI}注解。
	 */
	public static <T> ServiceLoader<T> load(Class<T> type) {
		if (type == null) {
			throw new IllegalArgumentException("Service type == null");
		}
		if (!type.isInterface()) {
			throw new IllegalArgumentException("Service type(" + type + ") is not interface!");
		}
		if (!withSPIAnnotation(type)) {
			throw new IllegalArgumentException("Service type(" + type + ") is not service, because WITHOUT @" +
					SPI.class.getSimpleName() + " Annotation!");
		}
		ServiceLoader<T> loader = (ServiceLoader<T>) SERVICE_LOADERS.get(type);
		if (loader == null) {
			SERVICE_LOADERS.putIfAbsent(type, new ServiceLoader<>(type));
			loader = (ServiceLoader<T>) SERVICE_LOADERS.get(type);
		}
		return loader;
	}

ServiceLoader 的构造方法如下。

先解析接口SPI注解的default作为该接口默认实现名,再通过getAdaptive()方法加载该接口的工厂类。

	private final IServiceFactory objectFactory;
	
	private ServiceLoader(Class<T> type) {
		this.type = type;

		String defaultName = null;
		final SPI annotation = type.getAnnotation(SPI.class);
		if (annotation != null) {
			String value = annotation.value();
			if ((value = value.trim()).length() > 0) {
				String[] names = NAME_SEPARATOR.split(value);
				if (names.length > 1) {
					throw new IllegalStateException("more than 1 default service name on service " + type.getName() +
							": " + Arrays.toString(names));
				}
				if (names.length == 1 && names[0].trim().length() > 0) {
					defaultName = names[0].trim();
				}
				if (!isValidServiceName(defaultName)) {
					throw new IllegalStateException("default name(" + defaultName + ") of service " + type.getName() +
							" is invalid!");
				}
			}
		}
		this.defaultName = defaultName;
		objectFactory = (type == IServiceFactory.class ? null : ServiceLoader.load(IServiceFactory.class).getAdaptive());
	}

getAdaptive()方法如下所示。

通过getServiceClasses()方法加载该接口配置的所有实现类。

	/**
	 * 取得Adaptive实例。
	 */
	public T getAdaptive() {
		getServiceClasses(); // 加载扩展点,保证会发现手写的AdaptiveClass
		
		...
	}

getServiceClasses()方法如下所示,getServiceClass(String name) 方法可按name获取对应实现类。

通过loadServiceClasses0()方法加载该接口配置的所有实现类,并维护在nameMapping中。

	private final AtomicReference<Map<String, Class<?>>> nameMapping = new AtomicReference<>();

	private Map<String, Class<?>> getServiceClasses() {
		Map<String, Class<?>> classes = nameMapping.get();
		if (classes == null) {
			synchronized (nameMapping) {
				classes = nameMapping.get();
				if (classes == null) { // double check
					loadServiceClasses0();
					classes = nameMapping.get();
				}
			}
		}
		return classes;
	}

	private Class<?> getServiceClass(String name) {
		if (name == null) {
			throw new IllegalArgumentException("Service name == null");
		}
		Class<?> clazz = getServiceClasses().get(name);
		if (clazz == null) {
			throw findServiceClassLoadException(name);
		}
		return clazz;
	}

loadServiceClasses0()方法如下所示。

通过getClassLoader()方法获取类加载器,通过类加载器的getResources()方法和接口全路径名获取SPI配置。

	private void loadServiceClasses0() {
		Map<String, Class<?>> serviceName2Class = new LinkedHashMap<>();
		Map<String, Map<String, String>> name2Attributes = new LinkedHashMap<>();
		String fileName = null;
		try {
			ClassLoader classLoader = getClassLoader();
			fileName = SERVICE_CONF_DIRECTORY + type.getName();
			Enumeration<URL> urls;
			if (classLoader != null) {
				urls = classLoader.getResources(fileName);
			} else {
				urls = ClassLoader.getSystemResources(fileName);
			}

			if (urls != null) { // 找到的urls为null,或是没有找到文件,即认为是没有找到扩展点
				while (urls.hasMoreElements()) {
					URL url = urls.nextElement();
					readService0(serviceName2Class, name2Attributes, classLoader, url);
				}
			}
		} catch (Throwable t) {
			logger.error("Exception when load service point(interface: " + type.getName() + ", description file: " +
					fileName + ").", t);
		}

		nameMapping.set(serviceName2Class);
		this.nameAttributesMapping = name2Attributes;
	}

getClassLoader()方法如下所示。

先获取当前线程的上下文类加载器,如果为空则返回 ServiceLoader类的类加载器。

	private static ClassLoader getClassLoader() {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		if (classLoader != null) {
			return classLoader;
		}
		classLoader = ServiceLoader.class.getClassLoader();
		if (classLoader != null) {
			return classLoader;
		}
		return classLoader;
	}

解决方案

1.业务方谨慎使用stream的parallel,手动指定子线程的类加载器

2.InfoCenter优化获取类加载器方式【待定】

3.InfoCenter优化判断类加载是否成功的逻辑

总结可能遇到类加载失败的情况

在Java中,除了parallelStream和CompletableFuture之外,还有几种使用异步线程的方式可能会遇到类加载器相关的问题:

1、ExecutorService: 当你使用ExecutorService(或其子类如ThreadPoolExecutor)来提交任务时,如果没有显式地设置线程的上下文类加载器,那么可能会遇到类加载器问题。

ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(() -> {
    // 可能需要设置上下文类加载器
    // ...
});

2、Thread: 直接创建一个新的Thread对象时,如果在该线程中加载类或资源,可能需要设置上下文类加载器。

new Thread(() -> {
    // 可能需要设置上下文类加载器
    // ...
}).start();

3、TimerTask: 使用java.util.Timer类执行定时任务时,也可能需要关注类加载器的问题。

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        // 可能需要设置上下文类加载器
        // ...
    }
}, delay, period);

4、ForkJoinPool: 如果直接使用ForkJoinPool来执行任务,同样需要注意类加载器的设置。

ForkJoinPool forkJoinPool = new ForkJoinPool();
forkJoinPool.submit(() -> {
    // 可能需要设置上下文类加载器
    // ...
});

5、ScheduledExecutorService: 使用ScheduledExecutorService来执行周期性任务时,类加载器的问题也需要考虑。

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(() -> {
    // 可能需要设置上下文类加载器
    // ...
}, initialDelay, period, TimeUnit.SECONDS);

6、Custom Thread Factory: 如果你使用自定义的线程工厂来创建线程,那么在工厂方法中设置类加载器是一个好习惯。

ExecutorService executorService = Executors.newFixedThreadPool(10, runnable -> {
    Thread thread = new Thread(runnable);
    thread.setContextClassLoader(contextClassLoader);
    return thread;
});

附录

参考示例

完整代码

<details>
<summary>完整代码</summary>

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;


public class ServiceLoader<T> {

	private static final Logger logger = LoggerFactory.getLogger(ServiceLoader.class);

	private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");

	private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_]+");

	private static final ConcurrentMap<Class<?>, ServiceLoader<?>> SERVICE_LOADERS = new ConcurrentHashMap<Class<?>, ServiceLoader<?>>();

	private static final Comparator<Object> ACTIVATE_COMPARATOR = (o1, o2) -> {
		if (o1 == null && o2 == null) {
			return 0;
		}
		if (o1 == null) {
			return -1;
		}
		if (o2 == null) {
			return 1;
		}
		if (o1.equals(o2)) {
			return 0;
		}
		Activate a1 = o1.getClass().getAnnotation(Activate.class);
		Activate a2 = o2.getClass().getAnnotation(Activate.class);
		if ((a1.before().length > 0 || a1.after().length > 0 || a2.before().length > 0 || a2.after().length > 0)
				&& o1.getClass().getInterfaces().length > 0
				&& o1.getClass().getInterfaces()[0].isAnnotationPresent(SPI.class)) {
			ServiceLoader<?> serviceLoader = ServiceLoader.load(o1.getClass().getInterfaces()[0]);
			if (a1.before().length > 0 || a1.after().length > 0) {
				String n2 = serviceLoader.getName(o2.getClass());
				for (String before : a1.before()) {
					if (before.equals(n2)) {
						return -1;
					}
				}
				for (String after : a1.after()) {
					if (after.equals(n2)) {
						return 1;
					}
				}
			}
			if (a2.before().length > 0 || a2.after().length > 0) {
				String n1 = serviceLoader.getName(o1.getClass());
				for (String before : a2.before()) {
					if (before.equals(n1)) {
						return 1;
					}
				}
				for (String after : a2.after()) {
					if (after.equals(n1)) {
						return -1;
					}
				}
			}
		}
		int n1 = a1.order();
		int n2 = a2.order();
		return n1 > n2 ? 1 : -1; // 就算n1 == n2也不能返回0,否则在HashSet等集合中,会被认为是同一值而覆盖
	};

	private static final ConcurrentMap<Class<?>, Object> SERVICE_INSTANCES = new ConcurrentHashMap<>();

	private static final ConcurrentMap<Class<? extends NameExtractor>, NameExtractor> EXTRACTOR_INSTANCES = new ConcurrentHashMap<>();

	private static final String SERVICE_CONF_DIRECTORY = "META-INF/spi/";

	private static final String PREFIX_ADAPTIVE_CLASS = "*";

	private static final String PREFIX_WRAPPER_CLASS = "+";

	private final AtomicReference<Map<String, Class<?>>> nameMapping = new AtomicReference<>();

	private final ConcurrentMap<Class<?>, List<String>> serviceProviderClassMapping = new ConcurrentHashMap<>();

	private final Class<T> type;

	private final String defaultName;

	private final IServiceFactory objectFactory;

	private final ConcurrentMap<String, AtomicReference<T>> instances = new ConcurrentHashMap<>();

	private final ConcurrentMap<String, AtomicReference<Throwable>> createInstanceErrors = new ConcurrentHashMap<>();

	private final AtomicReference<T> adaptiveInstance = new AtomicReference<>();

	private final AtomicReference<Throwable> createAdaptiveInstanceError = new AtomicReference<>();

	private final Map<String, Activate> activatesNames = Collections.synchronizedMap(new LinkedHashMap<>());

	private volatile Class<? extends T> adaptiveClass = null;

	private Map<String, IllegalStateException> classLoadExceptions = new ConcurrentHashMap<>();

	private volatile Map<String, Map<String, String>> nameAttributesMapping;

	private volatile Set<Class<? extends T>> wrapperClasses;


	private ServiceLoader(Class<T> type) {
		this.type = type;

		String defaultName = null;
		final SPI annotation = type.getAnnotation(SPI.class);
		if (annotation != null) {
			String value = annotation.value();
			if ((value = value.trim()).length() > 0) {
				String[] names = NAME_SEPARATOR.split(value);
				if (names.length > 1) {
					throw new IllegalStateException("more than 1 default service name on service " + type.getName() +
							": " + Arrays.toString(names));
				}
				if (names.length == 1 && names[0].trim().length() > 0) {
					defaultName = names[0].trim();
				}
				if (!isValidServiceName(defaultName)) {
					throw new IllegalStateException("default name(" + defaultName + ") of service " + type.getName() +
							" is invalid!");
				}
			}
		}
		this.defaultName = defaultName;
		objectFactory = (type == IServiceFactory.class ? null : ServiceLoader.load(IServiceFactory.class).getAdaptive());
	}

	/**
	 * {@link ServiceLoader}的工厂方法。
	 *
	 * @param type 扩展点接口类型
	 * @param <T>  扩展点类型
	 * @return {@link ServiceLoader}实例
	 * @throws IllegalArgumentException 参数为<code>null</code>;
	 *                                  或是扩展点接口上没有{@link SPI}注解。
	 */
	@SuppressWarnings("unchecked")
	public static <T> ServiceLoader<T> load(Class<T> type) {
		if (type == null) {
			throw new IllegalArgumentException("Service type == null");
		}
		if (!type.isInterface()) {
			throw new IllegalArgumentException("Service type(" + type + ") is not interface!");
		}
		if (!withSPIAnnotation(type)) {
			throw new IllegalArgumentException("Service type(" + type + ") is not service, because WITHOUT @" +
					SPI.class.getSimpleName() + " Annotation!");
		}

		ServiceLoader<T> loader = (ServiceLoader<T>) SERVICE_LOADERS.get(type);
		if (loader == null) {
			SERVICE_LOADERS.putIfAbsent(type, new ServiceLoader<>(type));
			loader = (ServiceLoader<T>) SERVICE_LOADERS.get(type);
		}
		return loader;
	}

	private static <T> boolean withSPIAnnotation(Class<T> type) {
		return type.isAnnotationPresent(SPI.class);
	}

	private static boolean isValidServiceName(String name) {
		return NAME_PATTERN.matcher(name).matches();
	}

	private static ClassLoader getClassLoader() {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		if (classLoader != null) {
			return classLoader;
		}
		classLoader = ServiceLoader.class.getClassLoader();
		if (classLoader != null) {
			return classLoader;
		}
		return classLoader;
	}

	private static String toString(Throwable throwable) {
		StringWriter w = new StringWriter(1024);
		PrintWriter p = new PrintWriter(w);
		try {
			throwable.printStackTrace(p);
			return w.toString();
		} finally {
			p.close();
		}
	}

	/**
	 * <code>
	 * "attrib1=value1,attrib2=value2,isProvider,order=3" =>
	 * {"attrib1"="value1", "attrib2"="value2", "isProvider"="", "order"="3"}
	 * </code>
	 */
	private static Map<String, String> parseServiceAttribute(String attribute) {
		Map<String, String> ret = new HashMap<String, String>();
		if (attribute == null || attribute.length() == 0) {
			return ret;
		}

		String[] parts = attribute.split(",");
		for (String part : parts) {
			part = part.trim();
			int idx = part.indexOf('=');
			if (idx > 0) {
				ret.put(part.substring(0, idx).trim(),
						part.substring(idx + 1).trim());
			} else {
				ret.put(part, "");
			}
		}

		return ret;
	}

	private static boolean isEmpty(String value) {
		return value == null || value.length() == 0 || "false".equalsIgnoreCase(value) || "0".equalsIgnoreCase(value)
				|| "null".equalsIgnoreCase(value) || "N/A".equalsIgnoreCase(value);
	}

	/**
	 * 获取扩展点实现的所有扩展点名。
	 */
	public Set<String> getNames() {
		Map<String, Class<?>> clazzes = getServiceClasses();
		return Collections.unmodifiableSet(clazzes.keySet());
	}

	/**
	 * 返回缺省的扩展点名,如果没有设置缺省则返回<code>null</code>。
	 */
	public String getDefaultName() {
		return defaultName;
	}

	/**
	 * 返回缺省的扩展。
	 *
	 * @throws IllegalStateException 指定的扩展没有设置缺省扩展点
	 */
	public T getDefault() {
		if (null == defaultName || defaultName.length() == 0) {
			throw new IllegalStateException("No default service on service " + type.getName());
		}
		return get(defaultName);
	}

	public T getOrDefault(String name) {
		name = (name == null || name.length() == 0) ? defaultName : name;
		return get(name);
	}

	/**
	 * 检查是否有指定名字的扩展。
	 *
	 * @param name 扩展名
	 * @return 有指定名字的扩展,则<code>true</code>,否则<code>false</code>。
	 * @throws IllegalArgumentException 参数为<code>null</code>或是空字符串。
	 */
	public boolean has(String name) {
		if (name == null || name.length() == 0) {
			throw new IllegalArgumentException("Service name == null");
		}
		return getServiceClasses().get(name) != null;
	}

	private Map<String, Class<?>> getServiceClasses() {
		Map<String, Class<?>> classes = nameMapping.get();
		if (classes == null) {
			synchronized (nameMapping) {
				classes = nameMapping.get();
				if (classes == null) { // double check
					loadServiceClasses0();
					classes = nameMapping.get();
				}
			}
		}
		return classes;
	}

	private Class<?> getServiceClass(String name) {
		if (name == null) {
			throw new IllegalArgumentException("Service name == null");
		}
		Class<?> clazz = getServiceClasses().get(name);
		if (clazz == null) {
			throw findServiceClassLoadException(name);
		}
		return clazz;
	}

	private IllegalStateException findServiceClassLoadException(String name) {
		String msg = "No such service " + type.getName() + " by name " + name;

		for (Map.Entry<String, IllegalStateException> entry : classLoadExceptions.entrySet()) {
			if (entry.getKey().toLowerCase().contains(name.toLowerCase())) {
				IllegalStateException e = entry.getValue();
				return new IllegalStateException(msg + ", cause: " + e.getMessage(), e);
			}
		}

		StringBuilder buf = new StringBuilder(msg);
		if (!classLoadExceptions.isEmpty()) {
			buf.append(", possible causes: ");
			int i = 1;
			for (Map.Entry<String, IllegalStateException> entry : classLoadExceptions.entrySet()) {
				buf.append("\r\n(");
				buf.append(i++);
				buf.append(") ");
				buf.append(entry.getKey());
				buf.append(":\r\n");
				buf.append(toString(entry.getValue()));
			}
		}
		return new IllegalStateException(buf.toString());
	}

	@SuppressWarnings("unchecked")
	private T createService(String name) {
		Class<?> clazz = getServiceClass(name);
		try {
			T instance = (T) SERVICE_INSTANCES.get(clazz);
			if (instance == null) {
				Constructor<?> constructor = clazz.getDeclaredConstructor();
				constructor.setAccessible(true);
				SERVICE_INSTANCES.putIfAbsent(clazz, constructor.newInstance());
				instance = (T) SERVICE_INSTANCES.get(clazz);
			}
			initializingService(injectService(instance));
			Set<Class<? extends T>> wrapperClasses = this.wrapperClasses;
			if (wrapperClasses != null && wrapperClasses.size() > 0) {
				for (Class<? extends T> wrapperClass : wrapperClasses) {
					Constructor<? extends T> constructor = wrapperClass.getDeclaredConstructor(type);
					constructor.setAccessible(true);
					instance = initializingService(injectService(constructor.newInstance(instance)));
				}
			}
			return instance;
		} catch (Throwable t) {
			throw new IllegalStateException("Fail to create service " + name + " of service point " + type.getName() +
					", cause: " + t.getMessage(), t);
		}
	}

	private T injectService(T instance) {
		if (objectFactory != null) {
			for (Field field : instance.getClass().getDeclaredFields()) {
				Resource inject = field.getAnnotation(Resource.class);
				if (inject != null) {
					Class<?> type = inject.type();
					String name = inject.name();
					if (type == Object.class) {
						type = field.getType();
					}
					try {
						Object object = objectFactory.getService(type, name);
						if (object != null) {
							field.setAccessible(true);
							field.set(instance, object);
						}
					} catch (Exception e) {
//							logger.error("Fail to inject via field " + field.getName() + " of interface to service " +
//									"implementation " + instance.getClass() + " for service point " + type.getName() +
//									", cause: " + e.getMessage(), e);
						throw new RuntimeException("Fail to inject via field " + field.getName() + " of interface to service " +
								"implementation " + instance.getClass() + " for service point " + type.getName(), e);
					}
				}
			}
		}

		return instance;
	}

	private T initializingService(T instance) {
		if (objectFactory != null) {
			for (Method method : instance.getClass().getDeclaredMethods()) {
				if (method.getAnnotation(PostConstruct.class) != null) {
					try {
						method.setAccessible(true);
						method.invoke(instance);
					} catch (Exception e) {
//							logger.error("Fail to inject InitMethod method " + method.getName() + " of interface to service " +
//									"implementation " + instance.getClass() + " for service point " + type.getName() +
//									", cause: " + e.getMessage(), e);
						throw new RuntimeException("Fail to inject InitMethod method " + method.getName() + " of interface to service " +
								"implementation " + instance.getClass() + " for service point " + type.getName(), e);
					}
				}
			}
		}

		return instance;
	}

	/**
	 * 获取指定名字的扩展实例。
	 *
	 * @param name 扩展名
	 * @return 指定名字的扩展实例
	 * @throws IllegalArgumentException 参数为<code>null</code>或是空字符串。
	 * @throws IllegalStateException    指定的扩展名没有对应的扩展点,异常栈中包含可能的原因。
	 * @since 0.1.0
	 */
	public T get(String name) {
		if (name == null || name.length() == 0) {
			throw new IllegalArgumentException("Service name == null");
		}
		// 先一下加载扩展点类,如果没有这个名字的扩展点类,会抛异常,
		// 这样不用创建不必要的Holder。
		getServiceClass(name);

		try {
			// 引入的Holder是为了下面用Holder作“细粒度锁”,而不是锁整个serviceInstances
			AtomicReference<T> holder = instances.get(name);
			if (holder == null) {
				instances.putIfAbsent(name, new AtomicReference<>());
				holder = instances.get(name);
			}
			AtomicReference<Throwable> throwableHolder = createInstanceErrors.get(name);
			if (throwableHolder == null) {
				createInstanceErrors.put(name, new AtomicReference<>());
				throwableHolder = createInstanceErrors.get(name);
			}

			if (throwableHolder.get() != null) {
				//fix 本次调用抛出异常,删除异常Holder,保证下一次能够继续加载,而不是一直hold住
				createInstanceErrors.remove(name);
				throw new IllegalStateException("Fail to get service " + name + " of service point " + type.getName() +
						", cause: " + throwableHolder.get().getMessage(), throwableHolder.get());
			}
			if (holder.get() == null) {
				synchronized (holder) {
					holder = instances.get(name);
					throwableHolder = createInstanceErrors.get(name);
					if (throwableHolder.get() != null) { // double check
						//fix 本次调用抛出异常,删除异常Holder,保证下一次能够继续加载,而不是一直hold住
						createInstanceErrors.remove(name);
						throw new IllegalStateException("Fail to get service " + name + " of service point " +
								type.getName() + ", cause: " + throwableHolder.get().getMessage(), throwableHolder.get());
					}
					if (holder.get() == null) {
						try {
							holder.set(createService(name));
						} catch (Throwable t) {
							throwableHolder.set(t);
							throw new IllegalStateException("Fail to get service " + name + " of service point " +
									type.getName() + ", cause: " + t.getMessage(), t);
						}
					}
				}
			}

			return holder.get();
		} catch (Exception e) {
			//fix 本次调用抛出异常,删除异常Holder,保证下一次能够继续加载,而不是一直hold住
			createInstanceErrors.remove(name);
			throw e;
		}
	}

	private void loadServiceClasses0() {
		Map<String, Class<?>> serviceName2Class = new LinkedHashMap<>();
		Map<String, Map<String, String>> name2Attributes = new LinkedHashMap<>();
		String fileName = null;
		try {
			ClassLoader classLoader = getClassLoader();
			fileName = SERVICE_CONF_DIRECTORY + type.getName();
			Enumeration<URL> urls;
			if (classLoader != null) {
				urls = classLoader.getResources(fileName);
			} else {
				urls = ClassLoader.getSystemResources(fileName);
			}

			if (urls != null) { // 找到的urls为null,或是没有找到文件,即认为是没有找到扩展点
				while (urls.hasMoreElements()) {
					URL url = urls.nextElement();
					readService0(serviceName2Class, name2Attributes, classLoader, url);
				}
			}
		} catch (Throwable t) {
			logger.error("Exception when load service point(interface: " + type.getName() + ", description file: " +
					fileName + ").", t);
		}

		nameMapping.set(serviceName2Class);
		this.nameAttributesMapping = name2Attributes;
	}

	private void readService0(Map<String, Class<?>> serviceName2Class, Map<String, Map<String, String>> name2Attributes,
							  ClassLoader classLoader, URL url) {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
			String line;
			while ((line = reader.readLine()) != null) {
				String config = line;

				// delete comments
				final int ci = config.indexOf('#');
				if (ci >= 0) {
					config = config.substring(0, ci);
				}
				config = config.trim();
				if (config.length() == 0) {
					continue;
				}
				String name = null;
				String body = null;
				String attribute = null;
				try {
					int i = config.indexOf('=');
					if (i > 0) {
						name = config.substring(0, i).trim();
						body = config.substring(i + 1).trim();
					}
					// 没有配置文件中没有扩展点名,从实现类的SPI注解上读取。
					if (name == null || name.length() == 0) {
						throw new IllegalStateException("missing service name, config value: " + config);
					}
					int j = config.indexOf("(", i);
					if (j > 0) {
						if (config.charAt(config.length() - 1) != ')') {
							throw new IllegalStateException("missing ')' of service attribute!");
						}
						body = config.substring(i + 1, j).trim();
						attribute = config.substring(j + 1, config.length() - 1);
					}

					Class<? extends T> clazz = Class.forName(body, true, classLoader).asSubclass(type);
					if (!type.isAssignableFrom(clazz)) {
						throw new IllegalStateException("Error when load service class(interface: " + type.getName() +
								", class line: " + clazz.getName() + "), class " + clazz.getName() +
								"is not subtype of interface.");
					}

					if (name.startsWith(PREFIX_ADAPTIVE_CLASS)) {
						if (adaptiveClass == null) {
							adaptiveClass = clazz;
						} else if (!adaptiveClass.equals(clazz)) {
							throw new IllegalStateException("More than 1 adaptive class found: " +
									adaptiveClass.getClass().getName() + ", " + clazz.getClass().getName());
						}
					} else {
						boolean isWrapper = name.startsWith(PREFIX_WRAPPER_CLASS);
						if (isWrapper) {
							try {
								clazz.getDeclaredConstructor(type);
								Set<Class<? extends T>> wrappers = wrapperClasses;
								if (wrappers == null) {
									wrapperClasses = new CopyOnWriteArraySet<>();
									wrappers = wrapperClasses;
								}
								wrappers.add(clazz);
							} catch (NoSuchMethodException e) {
								throw new IllegalStateException("wrapper class(" + clazz + ") has NO copy constructor!", e);
							}
						} else {
							String[] nameList = NAME_SEPARATOR.split(name);

							Activate activate = clazz.getAnnotation(Activate.class);
							if (activate != null) {
								activatesNames.put(nameList[0], activate);
							}

							for (String n : nameList) {
								if (!isValidServiceName(n)) {
									throw new IllegalStateException("name(" + n + ") of service " + type.getName() +
											"is invalid!");
								}

								try {
									clazz.getDeclaredConstructor();
								} catch (NoSuchMethodException e) {
									throw new IllegalStateException("service class(" + clazz + ") has NO default " +
											"constructor!", e);
								}
								if (serviceName2Class.containsKey(n)) {
									if (serviceName2Class.get(n) != clazz) {
										throw new IllegalStateException("Duplicate service " + type.getName() +
												" name " + n + " on " + clazz.getName() + " and " + clazz.getName());
									}
								} else {
									serviceName2Class.put(n, clazz);
								}
								name2Attributes.put(n, parseServiceAttribute(attribute));

								List<String> serviceNames = serviceProviderClassMapping.get(clazz);
								if (serviceNames == null) {
									serviceProviderClassMapping.put(clazz, serviceNames = new ArrayList<>(1));
								}
								serviceNames.add(n);
							}
						}
					}
				} catch (Throwable t) {
					IllegalStateException e = new IllegalStateException("Failed to load config line(" + line +
							") of config file(" + url + ") for service(" + type.getName() + "), cause: " +
							t.getMessage(), t);
					logger.warn("", e);
					if (name != null && name.startsWith(PREFIX_ADAPTIVE_CLASS)) {
						createAdaptiveInstanceError.set(t);
					}
					classLoadExceptions.put(line, e);
				}
			} // end of while read lines
		} catch (Throwable t) {
			logger.error("Exception when load service class(interface: " + type.getName() + ", class file: " + url +
					") in " + url, t);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (Throwable t) {
					// ignore
				}
			}
		}
	}

	/**
	 * 取得Adaptive实例。
	 */
	public T getAdaptive() {
		getServiceClasses(); // 加载扩展点,保证会发现手写的AdaptiveClass

		Throwable createError = createAdaptiveInstanceError.get();
		T adaptiveInstance = this.adaptiveInstance.get();
		if (null != createError) {
			throw new IllegalStateException("Fail to create adaptive service for service point " + type.getName() +
					", cause: " + createError.getMessage(), createError);
		}
		if (null != adaptiveInstance) {
			return adaptiveInstance;
		}

		synchronized (this.adaptiveInstance) {
			createError = createAdaptiveInstanceError.get();
			adaptiveInstance = this.adaptiveInstance.get();
			if (null != createError) { // double check
				throw new IllegalStateException("Fail to create adaptive service for service point " + type.getName() +
						", cause: " + createError.getMessage(), createError);
			}
			if (null != adaptiveInstance) {
				return adaptiveInstance;
			}

			try {
				this.adaptiveInstance.set(createAdaptiveService());
				return this.adaptiveInstance.get();
			} catch (Throwable t) {
				createAdaptiveInstanceError.set(t);
				throw new IllegalStateException("Fail to create adaptive service for service point " + type.getName() +
						", cause: " + t.getMessage(), t);
			}
		}
	}

	private T createAdaptiveService() {
		try {
			Constructor<? extends T> constructor = getAdaptiveServiceClass().getDeclaredConstructor();
			constructor.setAccessible(true);
			return injectService(constructor.newInstance());
		} catch (Throwable e) {
			throw new IllegalStateException("Can not create adaptive service " + type + ", cause: " + e.getMessage(), e);
		}
	}

	private Class<? extends T> getAdaptiveServiceClass() {
		if (adaptiveClass != null) {
			return adaptiveClass;
		}
		return adaptiveClass = createAdaptiveServiceClass();
	}

	@SuppressWarnings("unchecked")
	private Class<? extends T> createAdaptiveServiceClass() {
		String code = createAdaptiveServiceClassCode();
		ClassLoader classLoader = getClassLoader();
		ICompiler compiler = ServiceLoader.load(ICompiler.class).getAdaptive();
		return (Class<? extends T>) compiler.compile(code, classLoader);
	}

	private String createAdaptiveServiceClassCode() {
		StringBuilder codeBuidler = new StringBuilder();
		Method[] methods = type.getMethods();
		boolean hasAdaptiveAnnotation = false;
		for (Method m : methods) {
			if (m.isAnnotationPresent(Adaptive.class)) {
				hasAdaptiveAnnotation = true;
				break;
			}
		}
		// 完全没有Adaptive方法,则不需要生成Adaptive类
		if (!hasAdaptiveAnnotation) {
			throw new IllegalStateException("No adaptive method on service " + type.getName() + ", refuse to create the " +
					"adaptive class!");
		}
		codeBuidler.append("package " + type.getPackage().getName() + ";");
		codeBuidler.append("\nimport " + ServiceLoader.class.getName() + ";");
		codeBuidler.append("\npublic class " + type.getSimpleName() + "$Adpative" + " implements " +
				type.getCanonicalName() + " {");

		for (Method method : methods) {
			Class<?> rt = method.getReturnType();
			Class<?>[] pts = method.getParameterTypes();
			Class<?>[] ets = method.getExceptionTypes();

			Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
			StringBuilder code = new StringBuilder(512);
			if (adaptiveAnnotation == null) {
				code.append("throw new UnsupportedOperationException(\"method ").append(method.toString())
						.append(" of interface ").append(type.getName()).append(" is not adaptive method!\");");
			} else {
				int parameterTypeIndex = -1;
				for (int i = 0; i < pts.length; ++i) {
					if (Parameters.class.isAssignableFrom(pts[i])) {
						parameterTypeIndex = i;
						break;
					}
				}
				// 有类型为URL的参数
				if (parameterTypeIndex != -1) {
					// Null Point check
					String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"parameter == null\");",
							parameterTypeIndex);
					code.append(s);

					s = String.format("\n%s parameter = arg%d;", Parameters.class.getName(), parameterTypeIndex);
					code.append(s);
				}
				// 参数没有URL类型
				else {
					String attribMethod = null;

					// 找到参数的URL属性
					LBL_PTS:
					for (int i = 0; i < pts.length; ++i) {
						Method[] ms = pts[i].getMethods();
						for (Method m : ms) {
							String name = m.getName();
							if ((name.startsWith("get") || name.length() > 3) && Modifier.isPublic(m.getModifiers())
									&& !Modifier.isStatic(m.getModifiers()) && m.getParameterTypes().length == 0
									&& Parameters.class.isAssignableFrom(m.getReturnType())) {
								parameterTypeIndex = i;
								attribMethod = name;
								break LBL_PTS;
							}
						}
					}
					if (attribMethod == null) {
						throw new IllegalStateException("fail to create adative class for interface " + type.getName()
								+ ": not found parameter or parameter attribute in parameters of method " +
								method.getName());
					}

					// Null point check
					String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
							parameterTypeIndex, pts[parameterTypeIndex].getName());
					code.append(s);
					s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
							parameterTypeIndex, attribMethod, pts[parameterTypeIndex].getName(), attribMethod);
					code.append(s);

					s = String.format("%s parameter = arg%d.%s();", Parameters.class.getName(), parameterTypeIndex, attribMethod);
					code.append(s);
				}

				String[] value = adaptiveAnnotation.value();
				// 没有设置Key,则使用“扩展点接口名的点分隔 作为Key
				if (value.length == 0) {
					char[] charArray = type.getSimpleName().toCharArray();
					StringBuilder sb = new StringBuilder(128);
					for (int i = 0; i < charArray.length; i++) {
						if (Character.isUpperCase(charArray[i])) {
							if (i != 0) {
								sb.append(".");
							}
							sb.append(Character.toLowerCase(charArray[i]));
						} else {
							sb.append(charArray[i]);
						}
					}
					value = new String[]{sb.toString()};
				}

				code.append("\nString extractorName = null;");
				Class<? extends NameExtractor> extractorClazz = adaptiveAnnotation.extractor();
				if (extractorClazz != null) {
					NameExtractor nameExtractor;
					try {
						nameExtractor = EXTRACTOR_INSTANCES.get(extractorClazz);
						if (nameExtractor == null) {
							Constructor<? extends NameExtractor> constructor = extractorClazz.getDeclaredConstructor();
							constructor.setAccessible(true);
							EXTRACTOR_INSTANCES.putIfAbsent(extractorClazz, constructor.newInstance());
							nameExtractor = EXTRACTOR_INSTANCES.get(extractorClazz);
						}
					} catch (Exception e) {
						throw new IllegalStateException("fail to create adative class for interface " + type.getName()
								+ ": fail to create extractor instance " + extractorClazz.getName());
					}
					for (int i = 0; i < pts.length; ++i) {
						String methodName = nameExtractor.extract(pts[i]);
						if (methodName != null) {
							String s = String.format("\nif (extractorName == null && arg%d != null) extractorName = arg%d.%s();", i, i, methodName);
							code.append(s);
						}
					}

				}
				String defaultServiceName = defaultName;
				String getNameCode = null;
				for (int i = value.length - 1; i >= 0; --i) {
					if (i == value.length - 1) {
						if (null != defaultServiceName) {
							getNameCode = String.format("parameter.getParameter(extractorName == null ? \"%s\" : " +
									"extractorName + \".%s\", \"%s\")", value[i], value[i], defaultServiceName);
						} else {
							getNameCode = String.format("parameter.getParameter(extractorName == null ? \"%s\" : " +
									"extractorName + \".%s\")", value[i], value[i]);
						}
					} else {
						getNameCode = String.format("parameter.getParameter(extractorName == null ? \"%s\" : " +
								"extractorName + \".%s\", %s)", value[i], value[i], getNameCode);
					}
				}
				code.append("\nString serviceName = ").append(getNameCode).append(";");
				// check serviceName == null?
				String s = String.format("\nif(serviceName == null) throw new IllegalStateException(\"Fail to get service(%s) name " +
						"from parameter(\" + parameter.toString() + \") use keys(%s)\");", type.getName(), Arrays.toString(value));
				code.append(s);

				s = String.format("\n%s service = (%<s)%s.load(%s.class).get(serviceName);", type.getName(),
						ServiceLoader.class.getSimpleName(), type.getName());
				code.append(s);

				// return statement
				if (!rt.equals(void.class)) {
					code.append("\nreturn ");
				}

				s = String.format("service.%s(", method.getName());
				code.append(s);
				for (int i = 0; i < pts.length; i++) {
					if (i != 0) {
						code.append(", ");
					}
					code.append("arg").append(i);
				}
				code.append(");");
			}

			codeBuidler.append("\npublic " + rt.getCanonicalName() + " " + method.getName() + "(");
			for (int i = 0; i < pts.length; i++) {
				if (i > 0) {
					codeBuidler.append(", ");
				}
				codeBuidler.append(pts[i].getCanonicalName());
				codeBuidler.append(" ");
				codeBuidler.append("arg" + i);
			}
			codeBuidler.append(")");
			if (ets.length > 0) {
				codeBuidler.append(" throws ");
				for (int i = 0; i < ets.length; i++) {
					if (i > 0) {
						codeBuidler.append(", ");
					}
					codeBuidler.append(ets[i].getCanonicalName());
				}
			}
			codeBuidler.append(" {");
			codeBuidler.append(code.toString());
			codeBuidler.append("\n}");
		}
		codeBuidler.append("\n}");
		if (logger.isDebugEnabled()) {
			logger.debug(codeBuidler.toString());
		}
		return codeBuidler.toString();
	}

	public Map<String, Map<String, String>> getAttributes() {
		// 先一下加载扩展点类
		getServiceClasses();

		return nameAttributesMapping;
	}

	public Map<String, String> getAttribute(String name) {
		if (name == null || name.length() == 0) {
			throw new IllegalArgumentException("Service name == null");
		}

		// 先一下加载扩展点类,如果没有这个名字的扩展点类,会抛异常,
		// 这样不用创建不必要的Holder。
		getServiceClass(name);

		return nameAttributesMapping.get(name);
	}

	@Override
	public String toString() {
		return this.getClass().getName() + "<" + type.getName() + ">";
	}

	public List<T> getActivate(Parameters parameters, String key) {
		return getActivate(parameters, key, null);
	}

	public List<T> getActivate(Parameters parameters, Collection<String> values) {
		return getActivate(parameters, values, null);
	}

	public List<T> getActivate(Parameters parameters, String key, String group) {
		String value = parameters.getParameter(key);
		List<String> values = value == null || value.length() == 0 ? null : Arrays.asList(NAME_SEPARATOR.split(value));
		return getActivate(parameters, values, group);
	}

	public List<T> getActivate(Parameters parameters, Collection<String> values, String group) {
		List<T> services = new ArrayList<>();
		if (values == null) {
			values = Collections.EMPTY_LIST;
		}

		getServiceClasses();

		if (values.isEmpty()) {
			for (Map.Entry<String, Activate> entry : activatesNames.entrySet()) {
				String name = entry.getKey();
				Activate activate = entry.getValue();
				addActivateService(group, activate, name, parameters, services);
			}
			Collections.sort(services, ACTIVATE_COMPARATOR);
		} else {
			for (String name : values) {
				Activate activate = activatesNames.get(name);
				if (activate == null) {
					continue;
				}
				addActivateService(group, activate, name, parameters, services);
			}
		}
		return services;
	}

	private void addActivateService(String group, Activate activate, String name, Parameters parameters, List<T>
			services) {
		if (isMatchGroup(group, activate.group())) {
			T service = get(name);
			if (isActive(activate, parameters)) {
				services.add(service);
			}
		}
	}

	private boolean isMatchGroup(String group, String[] groups) {
		if (group == null || group.length() == 0) {
			return true;
		}
		if (groups != null && groups.length > 0) {
			for (String g : groups) {
				if (group.equals(g)) {
					return true;
				}
			}
		}
		return false;
	}

	private boolean isActive(Activate activate, Parameters parameters) {
		String[] keys = activate.value();
		if (keys.length == 0) {
			return true;
		}
		for (String key : keys) {
			for (Map.Entry<String, String> entry : parameters.getParameters().entrySet()) {
				String k = entry.getKey();
				String v = entry.getValue();
				if ((k.equals(key) || k.endsWith("." + key)) && !isEmpty(v)) {
					return true;
				}
			}
		}
		return false;
	}

	public String getName(T serviceProvider) {
		return getName(serviceProvider.getClass());
	}

	public String getName(Class<?> serviceProviderClass) {
		List<String> target = serviceProviderClassMapping.get(serviceProviderClass);
		if (target == null) {
			return null;
		}
		if (target.size() > 1) {
			throw new IllegalArgumentException("Service provider class: " + serviceProviderClass + " size great than 1");
		}
		return target.get(0);
	}

	public List<String> getNames(T serviceProvider) {
		return getNames(serviceProvider.getClass());
	}

	public List<String> getNames(Class<?> serviceProviderClass) {
		return serviceProviderClassMapping.get(serviceProviderClass);
	}

}

    
</details>