@SPI public interface Robot { void sayHello(); } public class OptimusPrime implements Robot{ @Override public void sayHello() { System.out.println("Hello, I am Optimus Prime."); } } public class Bumblebee implements Robot{ @Override public void sayHello() { System.out.println("Hello, I am Bumblebee."); } }
public class DubboSPITest { @Test public void sayHelloDubbo() throws Exception { ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class); Robot optimusPrime = extensionLoader.getExtension("optimusPrime"); optimusPrime.sayHello(); Robot bumblebee = extensionLoader.getExtension("bumblebee"); bumblebee.sayHello(); } }
輸出: Hello, I am Optimus Prime. Hello, I am Bumblebee.
ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class); public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if (!type.isInterface()) { throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); } if (!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); } // 從緩存中獲取與拓展類對應的ExtensionLoader ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); if (loader == null) { // 若緩存未命中,則建立一個新的實例,先簡單看下new ExtensionLoader<T>(type) EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }
這裏的objectFactory建立能夠參考: Dubbo的SPI機制分析3-Dubbo的IOC依賴注入java
private ExtensionLoader(Class<?> type) { this.type = type; // 這裏的type是Robot.class,因此會執行後面的代碼,加載並建立SpiExtensionFactory和SpringExtensionFactory, objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
public T getExtension(String name) { if ("true".equals(name)) { return getDefaultExtension(); } // Holder也是用於持有對象的,用做緩存 Holder<Object> holder = cachedInstances.get(name); if (holder == null) { cachedInstances.putIfAbsent(name, new Holder<Object>()); holder = cachedInstances.get(name); } Object instance = holder.get(); if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { // 建立拓展實例,下面分析createExtension(name) instance = createExtension(name); holder.set(instance); } } } return (T) instance; }
這裏依賴注入能夠參考: Dubbo的SPI機制分析3-Dubbo的IOC依賴注入segmentfault
private T createExtension(String name) { // 從配置文件中加載全部的拓展類,可獲得「配置項名稱」到「配置類」的映射關係表 // 加載完後根據name獲取,獲得形如com.alibaba.dubbo.demo.provider.spi.OptimusPrime // 待會重點分析getExtensionClasses(),刪去了一些非關鍵代碼 Class<?> clazz = getExtensionClasses().get(name); try { // 也是嘗試先從緩存獲取,獲取不到經過反射建立一個並放到緩存中 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } // 依賴注入和cachedWrapperClasses,後面分析 injectExtension(instance); Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && !wrapperClasses.isEmpty()) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } return instance; } }
private Map<String, Class<?>> getExtensionClasses() { // 從緩存中獲取映射關係表 Map<String, Class<?>> classes = cachedClasses.get(); // 雙重檢查 if (classes == null) { synchronized (cachedClasses) { classes = cachedClasses.get(); if (classes == null) { // 若緩存中沒有,去加載映射關係 classes = loadExtensionClasses(); cachedClasses.set(classes); } } } return classes; }
private Map<String, Class<?>> loadExtensionClasses() { // 獲取SPI註解,這裏的type是在調用getExtensionLoader方法時傳入的 final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { String value = defaultAnnotation.value(); if ((value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1) { // 拋異常 } // 獲取@SPI註解中的值,並緩存起來,能夠關注下,後面會用到 if (names.length == 1) cachedDefaultName = names[0]; } } Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); // 加載指定文件夾下的配置文件,META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/ loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); // 我是放在這個目錄下的 loadDirectory(extensionClasses, DUBBO_DIRECTORY); loadDirectory(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; }
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) { // fileName是META-INF/dubbo/com.alibaba.dubbo.demo.provider.spi.Robot String fileName = dir + type.getName(); try { Enumeration<java.net.URL> urls; ClassLoader classLoader = findClassLoader(); // 根據文件名加載全部同名文件 if (classLoader != null) { urls = classLoader.getResources(fileName); } else { urls = ClassLoader.getSystemResources(fileName); } if (urls != null) { while (urls.hasMoreElements()) { // 一個resourceURL就是一個文件 java.net.URL resourceURL = urls.nextElement(); loadResource(extensionClasses, classLoader, resourceURL); } } } }
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8")); try { String line; // 按行讀取配置內容 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(); } if (line.length() > 0) { // 真正的去加載類 loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name); } } } } } } }
標註1,這裏的能夠參考: Dubbo的SPI機制分析2-Adaptive詳解
標註2,這裏的能夠參考: Dubbo的SPI機制分析4-Dubbo經過Wrapper實現AOP
標註3,這裏的cachedActivates能夠參考: Dubbo的SPI機制分析5-Activate詳解緩存
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException { // clazz必須是type類型的,不然拋異常 if (!type.isAssignableFrom(clazz)) { } // 判斷clazz是否爲標註了@Adaptive註解,標註1 if (clazz.isAnnotationPresent(Adaptive.class)) { if (cachedAdaptiveClass == null) { cachedAdaptiveClass = clazz; } else if (!cachedAdaptiveClass.equals(clazz)) { // 拋異常,不能有多個標註有@Adaptive註解的類 } } // 判斷是不是Wrapper類型,標註2 else if (isWrapperClass(clazz)) { Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); }
// 程序進入此分支,代表clazz是一個普通的拓展類,Robot就是一個普通的拓展類 else { // 檢測clazz是否有默認的構造方法,若是沒有,則拋出異常 clazz.getConstructor(); if (name == null || name.length() == 0) { name = findAnnotationName(clazz); if (name.length() == 0) { // 拋異常 } }
String[] names = NAME_SEPARATOR.split(name); if (names != null && names.length > 0) { // 用於@Activate根據條件激活,標註3 Activate activate = clazz.getAnnotation(Activate.class); if (activate != null) { cachedActivates.put(names[0], activate); } for (String n : names) { if (!cachedNames.containsKey(clazz)) { cachedNames.put(clazz, n); } Class<?> c = extensionClasses.get(n); if (c == null) { // 存儲名稱到class的映射關係,這樣就解析好了一行 extensionClasses.put(n, clazz); } else if (c != clazz) { // 拋異常 } } } } }