Dubbo釋出過程中,擴充套件點的載入
在Dubbo服務釋出的過程中,第一次出現擴充套件點的載入是在doExportUrlsFor1Protocol()方法中,載入ConfiguratorFactory配置工廠。
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) .hasExtension(url.getProtocol())) { url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) .getExtension(url.getProtocol()).getConfigurator(url).configure(url); }
首先根據載入類型別獲取擴充套件類載入器,然後根據擴充套件點名稱獲取具體的擴充套件點。先從快取中獲取對應型別的擴充套件器,如果快取中不存在,則利用建構函式建立一個新的載入器,並放入到快取中。
public class ExtensionLoader<T> { private ExtensionLoader(Class<?> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); } 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<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; } public boolean hasExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); try { this.getExtensionClass(name); return true; } catch (Throwable t) { return false; } } private ExtensionLoader(Class<?> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); } public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { createAdaptiveInstanceError = t; throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t); } } } } else { throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } } return (T) instance; } private T createAdaptiveExtension() { try { return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e); } } }
呼叫過程為:
getExtensionClass(String name)
->getExtensionClass(String name)
建立DubboProtocol的過程為,其中包含多個Wrapper的包裝:
Dubbo是URL驅動的。
.getAdaptiveExtension():獲取的是自適應類,是根據@Adaptive擴充套件點,動態生成class code,並經過編譯生成的動態代理類。
另一個常用的方法是:getExtension:用來獲取寬擴充套件類例項。
Protocol是Protocol$Adaptive,實際呼叫的是DubboProtocol
ProxyFactoty是 ProxyFactoty$Adaptive,實際呼叫的是JavassistProxyFactory,用來生成代理類和呼叫者。
此處程式碼意思是:使用DubboProtocol協議在本地暴露一個使用JavassistProxyFactory生成的代理類的呼叫者。
private void exportLocal(URL url) {
if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
URL local = URL.valueOf(url.toFullString())
.setProtocol(Constants.LOCAL_PROTOCOL)
.setHost(LOCALHOST)
.setPort(0);
ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
}
}
injectExtension()方法,用來處理方法名帶有set()的方法,動態的設定處理引數。例如:此處的協議為動態,根據URL中配置的引數而定,所以添加了一個注入的方法。injectExtension()方法中,判斷到有set()開始的方法,通過Object object = objectFactory.getExtension(pt, property)得到一個動態代理類Type$Adaptive,然後將該動態代理物件設定到引數中
public class StubProxyFactoryWrapper implements ProxyFactory {
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
}
public class ExtensionLoader<T> {
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
}
另一個常用的方法是:getActivateExtension(URL url, String[] values, String group):獲取啟用點
@SPI
public interface ExtensionFactory {
}
@SPI註解,用來提供獲取ExtensionFactory的實現類:public class SpiExtensionFactory
其中的isWrapperClass判斷規則是:實現類的建構函式是否是包含載入類引數。如果是,則判斷為包裝類,並將包裝類新增到cachedWrapperClasses成員變數中,載入類中不新增。
@Adaptive註解:當某個類上標註@Adaptive註解時,在loadClass的過程中,由於判斷類上有@Adaptive註解,會將載入的類新增到cachedAdaptiveInstance成員變數中,作為在載入擴充套件點類時的返回物件。
注意 JavassistProxyFactory類中getInvoker()方法,final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
##
@Activate註解在Filter中有使用案例:
@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY)
public class CacheFilter implements Filter {
}
在呼叫export()方法的過程當中,首先對Filter進行了載入。
階段性總結export()過程:
在export()過程中,首先呼叫了包裝DubboProtocol的Wrapper類,包括三個類,由外到內依次是:QosProtocolWrapper、ProtocolListenerWrapper,ProtocolFilter,由外層逐級呼叫內層,再呼叫到ProtocolFilterWrapper類的時候,呼叫了一個構建呼叫鏈的方法, protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER)),其中Constants.SERVICE_FILTER_KEY=service.filter;Constants.PROVIDER = provider,其中,在URL的引數中,service.filter的value為null,所以在載入了filter的所有實現類之後,根據Activate的條件對Filter進行過濾;其中此處的過濾條件為 :group為group;在此過程中符合條件的Filtle有8個:
```java
0 = {ExceptionFilter@11068}
1 = {ClassLoaderFilter@11268}
2 = {EchoFilter@11442}
3 = {MonitorFilter@11832}
4 = {GenericFilter@11974}
5 = {TimeoutFilter@11997}
6 = {TraceFilter@12018}
7 = {ContextFilter@12032}
然後對Filter進行迴圈處理,迴圈建立invoker,並呼叫上一個invoker的invoker方法。
然後呼叫InjvmProtocol的export()方法進行服務暴露,構造了一個InjvmExporter物件
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
super(invoker);
this.key = key;//key=com.bail.user.service.IUserService:1.0.0
this.exporterMap = exporterMap;
exporterMap.put(key, this);//將InjvmExporter自己放入到了map容器中
}
在exportLocal方法返回的Exporter為一個ListenerExporterWrapper型別的,並將該物件放入到exporters容器中,exporters為ServiceBean的一個成員變數。
ServiceConfig處的export,protocol值為registry.
接下來看DubboProtocol的釋出過程:
構建DubboExporter
openServer