本文共 5905 字,大约阅读时间需要 19 分钟。
上一篇文章 分析了 Dubbo SPI 通过 getExtension(String name)
如何获取扩展点实现类对象, 本文接着通过剖析 Dubbo 源码的方式看一下 getAdaptiveExtension()
方法是如何获取自适应扩展点实例的.
// 1. 缓存的自适应扩展点实例 private final Holder
instance
变量createAdaptiveExtension
方法主动去创建, 并放入缓存return instance
public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError != null) { throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); 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; }
getAdaptiveExtensionClass
方法, 获取自适应扩展实现类, 并且实例化,最终获得一个实例 instance
injectExtension
方法, 判断 instance
是否依赖其他扩展实现类对象, 如果有的话,通过 setter
方法注入到instance
实例中private T createAdaptiveExtension() { try { // 第二步: getAdaptiveExtensionClass return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e); } }
getExtensionClasses
方法在上一篇文章 有讲到, cachedClasses
是否为空cachedClasses
private Class getAdaptiveExtensionClass() { // 这一步会 load 所有的扩展实现类 getExtensionClasses(); if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } // 第三步: 动态编译 return cachedAdaptiveClass = createAdaptiveExtensionClass(); }
// 第三步: 动态编译 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); } // 动态生成 Adaptive 代码 package com.nimo.spi.adaptive; import org.apache.dubbo.common.extension.ExtensionLoader; public class MyProtocol$Adaptive implements com.nimo.spi.adaptive.MyProtocol { public void export(org.apache.dubbo.common.URL arg0) { if (arg0 == null) throw new IllegalArgumentException("url == null"); org.apache.dubbo.common.URL url = arg0; String extName = url.getParameter("myKey"); if(extName == null) throw new IllegalStateException("Failed to get extension (com.nimo.spi.adaptive.MyProtocol) name from url (" + url.toString() + ") use keys([myKey])"); com.nimo.spi.adaptive.MyProtocol extension = (com.nimo.spi.adaptive.MyProtocol)ExtensionLoader.getExtensionLoader(com.nimo.spi.adaptive.MyProtocol.class).getExtension(extName); extension.export(arg0); } }
该方法就是对获取到的自适应扩展点实例, 注入其他实例
// 第四步: 注入其他实例 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; }
Dubbo SPI 中定义了很多缓存, 比如上一篇提到的
// 3. (缓存的)扩展实现类集合 private final Holder
还有本文中涉及的
// 1. 缓存的自适应扩展点实例 private final Holder
因此在获取一个扩展点实例时,
这是一个很普遍的缓存思路, 上一篇文章 getExtension
方法也是如此, 只不过本文多了一个 动态编译过程, 也刚好迎合了前面讲到的 的内容.
转载地址:http://ugpdz.baihongyu.com/