package com.taobao.tddl.common.utils.extension; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import org.apache.commons.lang.exception.ExceptionUtils; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * 包装{@linkplain ServiceLoader},提供SPI的获取方式 <br/> * jdk自带的{@linkplain ServiceLoader} * 存在一些局限,无法为SPI扩展定义排序规则,如果classpath存在多个SPI配置时,加载无法确定,所以包装一下允许以后替换实现 * * @see <a * href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">JDK5.0的自动发现机制实现</a> * @author jianghang 2013-9-13 下午3:38:30 * @since 5.0.0 */ public class ExtensionLoader<S> { private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String TDDL_DIRECTORY = "META-INF/tddl/"; private static Map<Class, Class> providers = Maps.newConcurrentMap(); /** * 指定classloader加载server provider * * @param service * @param loader * @return * @throws ExtensionNotFoundException */ public static <S> S load(Class<S> service, ClassLoader loader) throws ExtensionNotFoundException { return loadFile(service, null, loader); } /** * 加载server provider * * @param service * @return * @throws ExtensionNotFoundException */ public static <S> S load(Class<S> service) throws ExtensionNotFoundException { return loadFile(service, null, findClassLoader()); } /** * 加载server provider * * @param service * @return * @throws ExtensionNotFoundException */ public static <S> S load(Class<S> service, String activateName) throws ExtensionNotFoundException { return loadFile(service, activateName, findClassLoader()); } /** * 指定classloader加载server provider * * @param service * @param loader * @return * @throws ExtensionNotFoundException */ public static <S> S load(Class<S> service, String activateName, ClassLoader loader) throws ExtensionNotFoundException { return loadFile(service, activateName, loader); } /** * 获取所有的扩展类,按照{@linkplain Activate}定义的order顺序进行排序 * * @return */ public static <S> List<Class> getAllExtendsionClass(Class<S> service) { return findAllExtensionClass(service, null, findClassLoader()); } /** * 获取所有的扩展类,按照{@linkplain Activate}定义的order顺序进行排序 * * @return */ public static <S> List<Class> getAllExtendsionClass(Class<S> service, ClassLoader loader) { return findAllExtensionClass(service, null, loader); } private static <S> S loadFile(Class<S> service, String activateName, ClassLoader loader) { Class<?> extension = providers.get(service); if (extension == null) { synchronized (service) { extension = providers.get(service); if (extension == null) { List<Class> extensions = findAllExtensionClass(service, activateName, loader); if (extensions.isEmpty()) { throw new ExtensionNotFoundException("not found service provider for : " + service.getName()); } extension = extensions.get(extensions.size() - 1);// 最大的一个 } } } try { return service.cast(extension.newInstance()); } catch (InstantiationException e) { throw new ExtensionNotFoundException("not found service provider for : " + service.getName() + " caused by " + ExceptionUtils.getFullStackTrace(e)); } catch (IllegalAccessException e) { throw new ExtensionNotFoundException("not found service provider for : " + service.getName() + " caused by " + ExceptionUtils.getFullStackTrace(e)); } } private static <S> List<Class> findAllExtensionClass(Class<S> service, String activateName, ClassLoader loader) { List<Class> extensions = Lists.newArrayList(); try { loadFile(service, SERVICES_DIRECTORY, loader, extensions); loadFile(service, TDDL_DIRECTORY, loader, extensions); } catch (IOException e) { throw new ExtensionNotFoundException("not found service provider for : " + service.getName() + " caused by " + ExceptionUtils.getFullStackTrace(e)); } if (extensions.isEmpty()) { return extensions; } // 做一下排序 Collections.sort(extensions, new Comparator<Class>() { public int compare(Class c1, Class c2) { Integer o1 = 0; Integer o2 = 0; Activate a1 = (Activate) c1.getAnnotation(Activate.class); Activate a2 = (Activate) c2.getAnnotation(Activate.class); if (a1 != null) { o1 = a1.order(); } if (a2 != null) { o2 = a2.order(); } return o1.compareTo(o2); } }); if (activateName != null) { // 如果有激活条件 for (int i = extensions.size() - 1; i >= 0; i--) { Class clz = extensions.get(i); Activate activate = (Activate) clz.getAnnotation(Activate.class); if (activate != null && activateName.equals(activate.name())) { return Arrays.asList(clz); } } throw new ExtensionNotFoundException("not found service provider for : " + service.getName() + " activateName : " + activateName); } else { return extensions; } } private static void loadFile(Class<?> service, String dir, ClassLoader classLoader, List<Class> extensions) throws IOException { String fileName = dir + service.getName(); Enumeration<java.net.URL> urls; if (classLoader != null) { urls = classLoader.getResources(fileName); } else { urls = ClassLoader.getSystemResources(fileName); } if (urls != null) { while (urls.hasMoreElements()) { java.net.URL url = urls.nextElement(); try { BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8")); 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) { extensions.add(Class.forName(line, true, classLoader)); } } } catch (Throwable e) { // ignore } } } } private static ClassLoader findClassLoader() { return Thread.currentThread().getContextClassLoader(); } }