标签:客户端连接 集合 存在 cal 新建 == 本质 建立连接 demo
今天打算来讲一讲 Dubbo 服务远程调用。笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊。后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现。本地消费者无须知道远程服务具体的实现,消费者和提供者通过代理类来进行交互!!
简单看一段代码回顾一下动态代理:
public class MyInvocationHandler implements InvocationHandler{
private Object object;
public MyInvocationHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(object, args);
return result;
}
}
public static void main(String[] args) {
MyInvocationHandler handler = new MyInvocationHandler(stu);
// 生成代理类
Student proxy = (Student)Proxy.newProxyInstance(loader, interfaces, handler);
// 通过代理类调用 sayHello 方法
proxy.sayHello(message);
}
实现动态代理的核心步骤有两步:
1、自定义实现了 InvocationHandler 接口的 handler 类,并重写 invoke() 方法
2、调用 Proxy.newProxyInstance 方法创建代理类
我们最后在调用 proxy.sayHello() 的时候,代理类会调用 MyInvocationHandler 类的 invoke() 方法,invoke() 方法通过反射机制最终调用 sayHello() 方法。既然对动态代理的核心组成已经了然,接下来我们就结合这两点分析下 Dubbo 远程服务调用的实现。
在 【Dubbo源码阅读系列】之 Dubbo XML 配置加载 中我们分析了 Dubbo 解析 XML 配置文件的相关流程,其中
get() ==> init() ==> createProxy()
不要怀疑...crateProxy() 方法就是我们今天的主角...更令人激动的是,我们可以在该方法中找到与前文归纳的动态代理实现核心步骤相对应的代码实现:
java invoker = refprotocol.refer(interfaceClass, urls.get(0));
调用工厂类创建代理对象
java return (T) proxyFactory.getProxy(invoker);
在这一小节,我们只需要对代理类创建流程有个大致的印象即可,我们在后文深入分析具体流程。
invoker = refprotocol.refer(interfaceClass, urls.get(0));
熟悉的配方熟悉的料,通过 Dubbo SPI 机制我们发现这里调用的实际为 RegistryProtocol.refer(),问我为啥?详见:【Dubbo源码阅读系列】之 Dubbo SPI 机制
refprotocol.refer() 流程比较长,先放张时序图让大家有个基本的印象:
这里简单概括下上图中的重点内容:
java invoker = new InvokerDelegate<T>(protocol.refer(serviceType, url), url, providerUrl);
在上节中关于 invoker 的创建我们留了个小尾巴没有讲完。代码如下:
invoker = new InvokerDelegate<T>(protocol.refer(serviceType, url), url, providerUrl);
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
java return getExchanger(url).connect(url, handler);
java public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true); }
java return getTransporter().connect(url, handler);
java public Client connect(URL url, ChannelHandler listener) throws RemotingException { return new NettyClient(url, listener); }
终于要开始创建代理类了,回顾下 ReferenceConfig 中 createProxy() 方法最后一句:
return (T) proxyFactory.getProxy(invoker);
Invoker 对象的创建已经在第二小节详细分析过了。那么 proxyFactory 的 getProxy() 到底干了什么呢?实际上这里又借助了 Dubbo SPI 机制的实现。执行流程大致为:
proxyFactory.getProxy(invoker) ==》 StubProxyFactoryWrapper.getProxy(invoker) ==》AbstractProxyFactory.getProxy(invoker) ==》AbstractProxyFactory.getProxy(invoker, generic) ==> JavassistProxyFactory.getProxy(invoker, interfaces)
重点看 JavassistProxyFactory.getProxy() 方法:
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
这里有两点值得提一下:
Proxy.getProxy(interfaces) 使用了 javassist 字节码技术生成动态代理,类似的文章网上比较多,这里就不赘述了。生成的代理类如下所示:
```java
package org.apache.dubbo.common.bytecode;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.dubbo.common.bytecode.ClassGenerator.DC;
import org.apache.dubbo.demo.DemoService;
public class proxy0 implements DC, EchoService, DemoService {
public static Method[] methods;
private InvocationHandler handler;
public proxy0(InvocationHandler var1) {
this.handler = var1;
}
public proxy0() {
}
public String sayHello(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[0], var2);
return (String)var3;
}
public Object $echo(Object var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[1], var2);
return (Object)var3;
}
}选中某个 calss ,点击 Create .class File 就会在当前目录下创建一个 .class 文件了
小结:这一小节写的比较水~不过没关系,意思已经到了!!
标签:客户端连接 集合 存在 cal 新建 == 本质 建立连接 demo
原文地址:https://www.cnblogs.com/cfyrwang/p/10344925.html