Dubbo源碼閱讀筆記4
阿新 • • 發佈:2018-03-19
rem rec abstract provide jdk handle cal ssi info
### 發布服務到本地
發布本地服務的代碼在ServiceConfig.doExportUrlsFor1Protocol方法裏
主要代碼如下
// 通過動態代理工廠生成實現類調用器Invoker, Invoker相當於動態代理類 Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); // 只是將代理和配置放到一起 DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); // 發布服務到協議中,現在是InjvmProtocol Exporter<?> exporter = protocol.export(wrapperInvoker); exporters.add(exporter);
默認用的動態代理工廠是JavassistProxyFactory
通過AbstractProxyInvoker類封裝成Invoker
Wrapper是通過字節碼技術給類增加了幾個增強方法
想查看javassist生成的class源代碼可以通過CtClass類的writeFile方法輸出到本地文件,再反編譯
// JavassistProxyFactory.java public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { // TODO Wrapper類不能正確處理帶$的類名 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(‘$‘) < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; }
JdkProxyFactory則是直接用反射調用
// JdkProxyFactory.java public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { Method method = proxy.getClass().getMethod(methodName, parameterTypes); return method.invoke(proxy, arguments); } }; }
接下來就是把invoker發布
用的協議是InjvmProtocol
injvm協議非常簡單,不用監聽端口什麽的,直接返回InjvmExporter實例
到這裏發布服務到本地已經完成了
// InjvmProtocol.java
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
// InjvmExporter.java
class InjvmExporter<T> extends AbstractExporter<T> {
private final String key;
private final Map<String, Exporter<?>> exporterMap;
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
super(invoker);
this.key = key;
this.exporterMap = exporterMap;
exporterMap.put(key, this);
}
public void unexport() {
super.unexport();
exporterMap.remove(key);
}
}
### 調用本地服務
服務引用在初始化時生成目標接口的代理實現
在ReferenceConfig.createProxy方法生成
// ReferenceConfig.java
if (isJvmRefer) {
URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
// 通過服務協議獲取服務調用器, refprotocol和發布時的protocol是同一實例
invoker = refprotocol.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
}
// InjvmProtocol.java
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
// exporterMap保存了已發布的服務,因為發布和引用都用的同一個protocol實例,所以exporterMap也是同一個。
return new InjvmInvoker<T>(serviceType, url, url.getServiceKey(), exporterMap);
}
創建動態代理返回
默認用的動態代理工廠是JavassistProxyFactory,用字節碼技術生成目標接口的代理類
如果使用JdkProxyFactory,則沒有字節碼生成類的步驟,直接動態代理調用Invoker類的invoke方法
// ReferenceConfig.java
// 創建服務代理
return (T) proxyFactory.getProxy(invoker);
// JavassistProxyFactory.java
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
// JdkProxyFactory.java
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
// 重點**
// javassist生成的類繼承自Proxy,並實現了目標接口,目標方法會被實現一次,handler是上面的InvokerInvocationHandler實例
// 以下是生成的方法
public String sayHello(String $1) {
Object[] args = new Object[1];
args[0] = ($w)$1;
Object ret = handler.invoke(this, methods[0], args);
return (java.lang.String)ret;
}
// InvokerInvocationHandler.java
// 該類實現了InvocationHandler,目的是支持jdk動態代理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
最後在調用目標方法的時候,通過調用方invoker找到服務方invoker
// InjvmInvoker.java
// 此時在調用方invoker實例
public Result doInvoke(Invocation invocation) throws Throwable {
// 通過exporterMap找到服務方exporter
Exporter<?> exporter = InjvmProtocol.getExporter(exporterMap, getUrl());
if (exporter == null) {
throw new RpcException("Service [" + key + "] not found.");
}
RpcContext.getContext().setRemoteAddress(NetUtils.LOCALHOST, 0);
// 拿出服務方invoker並調用方法
return exporter.getInvoker().invoke(invocation);
}
Dubbo源碼閱讀筆記4