(SPI)3.dubbo spi代碼分析

看三個(gè)方法,靜態(tài)擴(kuò)展類,adapter擴(kuò)展類,activate擴(kuò)展類。
先看getExtension

        Protocol dubbo = ExtensionLoader.getExtensionLoader(Protocol.class)
                .getExtension("dubbo");
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        // 維護(hù)了一個(gè)緩存,多次調(diào)用獲取擴(kuò)展器不會(huì)重復(fù)new
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
// 1、ExtensionLoader會(huì)維護(hù)一個(gè)objectFactory,objectFactory也是spi機(jī)制獲取的
//spi依賴注入的時(shí)候,會(huì)通過(guò)objectFactory獲取到其他的spi對(duì)象注入進(jìn)去
//2、獲取到的可適配擴(kuò)展對(duì)象AdaptiveExtensionFactory效果就是遍歷所有的
//ExtensionFactory實(shí)現(xiàn)類來(lái)獲取對(duì)象。
// 3、ExtensionFactory有兩個(gè)具體的實(shí)現(xiàn)類SpringExtensionFactory,
// SpiExtensionFactory。一個(gè)是從SPI獲取,一個(gè)是從spring容器獲取對(duì)象。所以說(shuō)
// spi的依賴注入的時(shí)候,會(huì)從這兩個(gè)地方獲取對(duì)象注入進(jìn)去。
// 4、相關(guān)SpiExtensionFactory、SpringExtensionFactory代碼比較簡(jiǎn)單,不貼了
    private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

獲取實(shí)現(xiàn)類對(duì)象,通過(guò)名稱。
這里有個(gè)小設(shè)計(jì)值得說(shuō)一下,這里使用了Holder包裹了instance。假設(shè)直接緩存instance如下。則為了防止并發(fā),多次掃描創(chuàng)建對(duì)象,則需要鎖住整個(gè)cacheInstances緩存。而使用Holder包裹一下,則只需要鎖住Holder就可以了

T instance = cachedInstances.get(name);
if (instance == null){
    synchronized(cacheInstances){
      instance  = cachedInstances.get(name);
      if(instance == null){
        // 創(chuàng)建對(duì)象
      }
  }
}
 public T getExtension(String name) {
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
private T createExtension(String name) {
      // getExtensionClasses方法會(huì)真正掃描meta-inf文件并加載class
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            // 依賴注入。
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
          // 初始化。如果對(duì)象實(shí)現(xiàn)類Lifecycle生命周期接口,則調(diào)用這個(gè)接口的初始化方法initialize
            initExtension(instance);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }
 private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();

        for (LoadingStrategy strategy : strategies) {
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }

Dubbo的spi的獲取加載策略,是通過(guò)java的spi獲取的。

 private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();

   private static LoadingStrategy[] loadLoadingStrategies() {
        return stream(load(LoadingStrategy.class).spliterator(), false)
                .sorted()
                .toArray(LoadingStrategy[]::new);
    }
image.png

3個(gè)LoadingStrategy,分別指定了不同的目錄。

public class DubboLoadingStrategy implements LoadingStrategy {

    @Override
    public String directory() {
        return "META-INF/dubbo/";
    }

    @Override
    public boolean overridden() {
        return true;
    }

    @Override
    public int getPriority() {
        return NORMAL_PRIORITY;
    }


}

分析是否存在Adaptive注解:用成員變量維護(hù)Adaptive的class
是否是WrapperClass(構(gòu)造方法傳參是Type這個(gè)接口類型):用成員變量維護(hù)
如果存在Extension注解(這個(gè)注解自定義name)
是否存在Activate注解,是則緩存起來(lái):用map維護(hù)。
緩存所有的class。

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWr55¥¥apperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }

injectExtension,依賴注入就是遍歷set方法,用objectFactory從spi或spring中獲取需要的對(duì)象注入進(jìn)去。

private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * Check {@link DisableInject} to see if we need auto injection for this property
                 */
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    String property = getSetterProperty(method);
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error("Failed to inject via method " + method.getName()
                            + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }

            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

至此,getExtension方法看完了。

看一下getAdaptiveExtension獲取自適應(yīng)擴(kuò)展類。
主要代碼:

public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
               synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
  // 前面說(shuō)了在加載meta-inf配置文件然后加載Class類的時(shí)候,如果類上有
//@Adaptive注解,就會(huì)把這個(gè)類賦值給cachedAdaptiveInstance。
 // 所以如果這里為空,則會(huì)創(chuàng)建一個(gè)代理類,不為空,則直接把加了@Adaptive的類返回。
               if (instance == null) {
                    try {
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }

        return (T) instance;
    }
private Class<?> createAdaptiveExtensionClass() {
       // 生成代碼,編譯加載
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

動(dòng)態(tài)生成的代理類代碼大概如下,會(huì)根據(jù)url參數(shù)動(dòng)態(tài)指定調(diào)用哪個(gè)實(shí)現(xiàn)類的方法。

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, 
                                              org.apache.dubbo.common.URL arg1) 
            throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null 
                ? "dubbo" : url.getProtocol());
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) 
                ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class)
                        .getExtension(extName);
        return extension.refer(arg0, arg1);
    }

至此getAdaptiveExtension也看完了。
再看看getActivateExtension方法。

        URL url = new URL("", "", 0);
        url = url.addParameter("ab", "cache");
        List<Filter> filters = loader.getActivateExtension(url, "ab");
  public List<T> getActivateExtension(URL url, String key, String group) {
      // 從url中以傳入的參數(shù)key,獲取指定的value
        String value = url.getParameter(key);
        return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
    }
 public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> activateExtensions = new ArrayList<>();
        List<String> names = values == null ? new ArrayList<>(0) : asList(values);
        if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
        // 掃描和加載class   
         getExtensionClasses();
            for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
                // 擴(kuò)展類的名字,比如cacheFilter,name就是cache
                String name = entry.getKey();
                // Activate注解對(duì)象
                Object activate = entry.getValue();

                String[] activateGroup, activateValue;
            // 先添加group匹配,name
                if (activate instanceof Activate) {
                    activateGroup = ((Activate) activate).group();
                    activateValue = ((Activate) activate).value();
                } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
                    activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
                    activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
                } else {
                    continue;
                }
// 座一層適配過(guò)濾
                if (isMatchGroup(group, activateGroup)
                        && !names.contains(name)
                        && !names.contains(REMOVE_VALUE_PREFIX + name)
                        && isActive(activateValue, url)) {
                    activateExtensions.add(getExtension(name));
                }
            }
            activateExtensions.sort(ActivateComparator.COMPARATOR);
        }
// 再根據(jù)傳參,把擴(kuò)展類后添加進(jìn)來(lái),比如傳參cache,cacheFilter就會(huì)在這里后添加進(jìn)來(lái)
        List<T> loadedExtensions = new ArrayList<>();
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            if (!name.startsWith(REMOVE_VALUE_PREFIX)
                    && !names.contains(REMOVE_VALUE_PREFIX + name)) {
                if (DEFAULT_KEY.equals(name)) {
                    if (!loadedExtensions.isEmpty()) {
                        activateExtensions.addAll(0, loadedExtensions);
                        loadedExtensions.clear();
                    }
                } else {
                    loadedExtensions.add(getExtension(name));
                }
            }
        }
        if (!loadedExtensions.isEmpty()) {
            activateExtensions.addAll(loadedExtensions);
        }
        return activateExtensions;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容