0
点赞
收藏
分享

微信扫一扫

Dubbo 之 Invoker


相关博客:

​​Spring 自定义 XML 配置扩展​​

​​Dubbo的SPI机制(二)(Dubbo优化后的SPI实现)​​

​​Dubbo 的 SPI 机制(三)(Extension 扩展点补充)​​

​​Dubbo 之服务发布和注册(一)​​

​​Dubbo 之服务发布和注册(二)(补充)​​

 

在 Dubbo 官方文档中有这么一段介绍:

在 Dubbo 的核心领域模型中:

  • Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。
  • Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
  • Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。

在之前博客中分析的 com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol 中有这么一段代码:

Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

这个 proxyFactory 也是一个扩展点,而且是一个自适应的扩展点:

private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

结合之前的分析,自适应的扩展点可以大致这么来看:

Dubbo 之 Invoker_自适应

由于会存在各种各样的协议,而且还有未知的用户的扩展的协议,如果在程序里面判断是很复杂的,所以这里做了一个适配,根据传过来的协议自动适配相应的处理类。

这里的自适应 proxyFactory,在之前的博客中也提到过自适应扩展点有两种,一种是 Dubbo 已经写好了,一种是动态生成的。看看 ProxyFactory 接口:

/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;

/**
* ProxyFactory. (API/SPI, Singleton, ThreadSafe)
*
* @author william.liangf
*/
@SPI("javassist")
public interface ProxyFactory {

/**
* create proxy.
*
* @param invoker
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException;

/**
* create invoker.
*
* @param <T>
* @param proxy
* @param type
* @param url
* @return invoker
*/
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

也就是说 ProxyFactory 的自适应扩展点是动态生成的,即这里的 proxyFactory 就是 ProxyFactory$Adaptive。在 com.alibaba.dubbo.common.extension.ExtensionLoader#createAdaptiveExtensionClass 上加上断点:

Dubbo 之 Invoker_java_02

ProxyFactory$Adaptive 内容为:

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.ExtensionLoader;


public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory {
public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0,
java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)
throws java.lang.Object {
if (arg2 == null) {
throw new IllegalArgumentException("url == null");
}

com.alibaba.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");

if (extName == null) {
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" +
url.toString() + ") use keys([proxy])");
}

com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class)
.getExtension(extName);

return extension.getInvoker(arg0, arg1, arg2);
}

public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0)
throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null) {
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.Invoker argument == null");
}

if (arg0.getUrl() == null) {
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
}

com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");

if (extName == null) {
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" +
url.toString() + ") use keys([proxy])");
}

com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class)
.getExtension(extName);

return extension.getProxy(arg0);
}
}

结合上面的代码。这里会调用 proxyFactory 的 getInvoker() 方法:

public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0,
java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)
throws java.lang.Object {
if (arg2 == null) {
throw new IllegalArgumentException("url == null");
}

com.alibaba.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");

if (extName == null) {
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" +
url.toString() + ") use keys([proxy])");
}

com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class)
.getExtension(extName);

return extension.getInvoker(arg0, arg1, arg2);
}

还是获取扩展点,这里是根据指定名称 extName 来的。extName 是根据:

String extName = url.getParameter("proxy", "javassist");

也就是说当 url 中没有 proxy 参数的话,就会是 javassist。可以看看 javassist 对应的扩展点:

Dubbo 之 Invoker_字节码_03

这里就是动态字节码的生成工厂。还可以看到 StubProxyFactoryWrapper,这就是一个装饰器了。跟之前的套路就差不多了。

看看 JavassistProxyFactory 的 getInvoker() 方法:

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);
}
};
}

先看看 Wrapper.getWrapper() 做了些什么:

Dubbo 之 Invoker_java_04

makeWrapper() 方法就是 Javassist 动态字节码生成工具做的一些事情:

private static Wrapper makeWrapper(Class<?> c)
{
if( c.isPrimitive() )
throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

String name = c.getName();
ClassLoader cl = ClassHelper.getCallerClassLoader(Wrapper.class);

StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
......
......
ClassGenerator cc = ClassGenerator.newInstance(cl);
cc.setClassName( ( Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw" ) + id );
cc.setSuperClass(Wrapper.class);

cc.addDefaultConstructor();
......
......
catch(Throwable e)
{
throw new RuntimeException(e.getMessage(), e);
}
finally
{
cc.release();
ms.clear();
mns.clear();
dmns.clear();
}
}

最后都会封装成这个 ClassGenerator cc,在 cc 处打个断点:

Dubbo 之 Invoker_java_05

看看 c1、c2、c3:

//c1
public void setPropertyValue(Object o, String n, Object v) {
dongguabai.dubbo.IHello w;
try {
w = ((dongguabai.dubbo.IHello) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + $2 + "\" filed or setter method in class dongguabai.dubbo.IHello.");
}

//c2
public Object getPropertyValue(Object o, String n) {
dongguabai.dubbo.IHello w;
try {
w = ((dongguabai.dubbo.IHello) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + $2 + "\" filed or setter method in class dongguabai.dubbo.IHello.");
}

//c3
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
dongguabai.dubbo.IHello w;
try {
w = ((dongguabai.dubbo.IHello) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
try {
if ("sayHello".equals($2) && $3.length == 1) {
return ($w) w.sayHello((java.lang.String) $4[0]);
}
} catch (Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + $2 + "\" in class dongguabai.dubbo.IHello.");
}

这个 cc 就是服务端返回的 Invoker 对象的动态字节码。com.alibaba.dubbo.common.bytecode.Wrapper#makeWrapper 方法最终返回的 Wrapper 就是这么来的:

Dubbo 之 Invoker_自适应_06

再接着看 com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker:

Dubbo 之 Invoker_自适应_07

最终调用的是 wrapper 的 invokeMethod() 方法,这个方法结合上面的 c3,最终会调用服务端的 sayHello() 方法。

再回到 com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol 方法,在 invoker 对象处加一个断点:

Dubbo 之 Invoker_java_08

有一个动态生成的 wrapper,一个服务端的服务实例。

 

参考资料:

​​http://dubbo.apache.org/zh-cn/docs/dev/design.html​​


举报

相关推荐

0 条评论