1.查看源码
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("hello-world-app-customer");
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://192.168.133.129:2181");
// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接
// 引用远程服务
ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
reference.setApplication(application);
reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
reference.setInterface(DemoService.class);
reference.setVersion("1.0.0");
// 和本地bean一样使用xxxService
DemoService demoService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
String say = demoService.say("World");
System.out.println(say);
1.通过前面的Provider的源码发现其中的ApplicationConfig和RegistryConfig以及ReferenceConfig只是前期的配置工作
2.通过debug发现reference.get()这个方法的调用
,返回的DemoService的结果是一个代理对象,而这个代理对象实际上是使用jdk的接口代理实现的
,所以它的实现方法为Invoke,通过查看控制台打印的信息发现当前的get方法实际上会连接Zookeeper(检查其连通性)
3.所以档期那的demoService
.say实际上是使用代理方式实现的,其类型为org.apache.dubbo.common.bytecode.proxy0@226642a5
4.通过debug发现当前的proxy代理类中具有一个handler
其实际类型为InvokerInvocationHandler类型
2.查看InvokerInvocationHandler中的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();//获取当前调用方法的名称
Class<?>[] parameterTypes = method.getParameterTypes();//获取当前调用接口需要的参数类型
if (method.getDeclaringClass() == Object.class) {//判断当前方法的类型是否为object类型
return method.invoke(invoker, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();//判断当前调用的方法是否为toString方法
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();//判断当前调用的方法名是否为hashCode方法
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);//判断当前调用的方法名称是否为equals方法
}
//调用代理类的invoke方法,通过debug发现实际上调用的是MockClusterInvoker<T>中的invoke方法
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
2.1 查看MockClusterInvoker类的invoke方法
@Override
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;//定义返回的结果
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();//
if (value.length() == 0 || value.equalsIgnoreCase("false")) {
//no mock
result = this.invoker.invoke(invocation);//发现实际上调用的是这个方法:FailoverClusterInvoker类中的invoke方法,
} else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
}
//force:direct mock
result = doMockInvoke(invocation, null);
} else {
//fail-mock
try {
result = this.invoker.invoke(invocation);
} catch (RpcException e) {
if (e.isBiz()) {
throw e;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
}
result = doMockInvoke(invocation, e);
}
}
return result;
}
通过debug发现当前实际上调用的是FailoverClusterInvoker类中的invoke方法
,但是当前类FailoverClusterInvoker没有这个方法只有一个doInvoke方法
,所以断定当前的invoke方法实际上是抽象父类的方法
,实际上还是调用doInvoke方法
2.2 查看FailoverClusterInvoker的doInvoke方法
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
List<Invoker<T>> copyInvokers = invokers;
checkInvokers(copyInvokers, invocation);//检查调用的方法是否存在
String methodName = RpcUtils.getMethodName(invocation);//桶过工具获取调用方法的方法名
int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;//获取方法名的长度这里为say所以长度都为3
if (len <= 0) {
len = 1;
}
// retry loop.
RpcException le = null; // last exception.//定义异常
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.//创建当前需要调用方法的列表
Set<String> providers = new HashSet<String>(len);
for (int i = 0; i < len; i++) {//循环3次
//Reselect before retry to avoid a change of candidate `invokers`.
//NOTE: if `invokers` changed, then `invoked` also lose accuracy.
if (i > 0) {//当i>0的是否做的事情
checkWhetherDestroyed();//检查当前是否销毁
copyInvokers = list(invocation);
// check again
checkInvokers(copyInvokers, invocation);//检查需要调用的方法是否存在
}
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);//通过查询获取实际需要调用的方法或者访问的url(使用dubbo协议的)dubbo://192.168.133.1:20880/com.hy.dubbo.api.DemoService
invoked.add(invoker);//然后向需要调用的invokes集合中添加已经调用的方法
RpcContext.getContext().setInvokers((List) invoked);
try {
Result result = invoker.invoke(invocation);//实际调用方法并获取返回值结果
if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + methodName
+ " in the service " + getInterface().getName()
+ " was successful by the provider " + invoker.getUrl().getAddress()
+ ", but there have been failed providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Last error is: "
+ le.getMessage(), le);
}
return result;
} catch (RpcException e) {
if (e.isBiz()) { // biz exception.
throw e;
}
le = e;
} catch (Throwable e) {
le = new RpcException(e.getMessage(), e);
} finally {
providers.add(invoker.getUrl().getAddress());
}
}
throw new RpcException(le.getCode(), "Failed to invoke the method "
+ methodName + " in the service " + getInterface().getName()
+ ". Tried " + len + " times of the providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ Version.getVersion() + ". Last error is: "
+ le.getMessage(), le.getCause() != null ? le.getCause() : le);
}
通过debug发现当前的invoker.invoke(invocation);中的invokerde 实际类型为ProtocolFilterWrapper中的静态类CallbackRegistrationInvoker中的invoke方法
2.3 查看ProtocolFilterWrapper.CallbackRegistrationInvoker中的invoke方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult = filterInvoker.invoke(invocation);//发现实际上调用的是ListenerInvokerWrapper中的invoke方法
asyncResult = asyncResult.whenCompleteWithContext((r, t) -> {
for (int i = filters.size() - 1; i >= 0; i--) {
Filter filter = filters.get(i);
// onResponse callback
if (filter instanceof ListenableFilter) {
Filter.Listener listener = ((ListenableFilter) filter).listener();
if (listener != null) {
if (t == null) {
listener.onResponse(r, filterInvoker, invocation);
} else {
listener.onError(t, filterInvoker, invocation);
}
}
} else {
filter.onResponse(r, filterInvoker, invocation);
}
}
});
return asyncResult;
}
通过源码发现当前实际上调用的是ListenerInvokerWrapper中的invoke方法
2.4 查看ListenerInvokerWrapper中的invoke方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
return invoker.invoke(invocation);//发现又是一个代理类,通过debug返现调用的是DubboInvoker
}
通过debug发现实际上调用的DubboInvoker类的invoke方法
2.5 查看DubboInvoker类的invoke方法
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;//创建RPC执行器
final String methodName = RpcUtils.getMethodName(invocation);//通过RpcUtils获取当前的调用的方法名
inv.setAttachment(PATH_KEY, getUrl().getPath());//设置当前调用的方式
inv.setAttachment(VERSION_KEY, version);//设置当前的版本
ExchangeClient currentClient;//创建交换客户端
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);//获取执行方法的超时时间默认为1000ms
if (isOneway) {//为false
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else {
AsyncRpcResult asyncRpcResult = new AsyncRpcResult(inv);//创建一个异步的Rpc结果
CompletableFuture<Object> responseFuture = currentClient.request(inv, timeout);//通过交换客户端进行发送请求,并获得响应的记过
asyncRpcResult.subscribeTo(responseFuture);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(responseFuture);
return asyncRpcResult;
}
} catch (TimeoutException e) {//捕获超时异常
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (RemotingException e) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
通过debug发现当前的DubboInvoker类中的Invoker方法实际上就是创建一个交换客户端,通过交换客户端发送请求并获得结果currentClient.request(inv, timeout);
2.6 查看HeaderExchangeClient中的request方法
@Override
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
return channel.request(request, timeout);
}
通过debug发现发现channel为HeaderExchangeChannel类型
2.7 查看HeaderExchangeChannel中的request方法
@Override
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
if (closed) {//判断当前的交换机是否关闭
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
// create request.
Request req = new Request();//开始创建一个请求
req.setVersion(Version.getProtocolVersion());//设置版本信息
req.setTwoWay(true);//设置是否为第二个方法
req.setData(request);//设置请求的数据
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);//创建一个执行器
try {
channel.send(req);//开始发送请求
} catch (RemotingException e) {
future.cancel();//出现问题后就取消请求
throw e;
}
return future;
}
1.发现当前的HeaderExchangeChannel中的request方法会创建一个Request类封装请求,然后通过channel.send(req)发送请求,所以执行后返回的结果在DefaultFuture中
2.通过debug发现当前的channel的实际类型为NettyClient
,但是其没有任何关于send方法,所以这个方法在于父类中
2.8 查看NettyClient的父类的AbstractClient中的send方法
@Override
public void send(Object message, boolean sent) throws RemotingException {
if (needReconnect && !isConnected()) {
connect();
}
Channel channel = getChannel();//获取发送信息的管道
//TODO Can the value returned by getChannel() be null? need improvement.
if (channel == null || !channel.isConnected()) {
throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl());
}
channel.send(message, sent);//发送信息
}
通过源码发现message:Request [id=1, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=say
, parameterTypes=[class java.lang.String], arguments=[World]
, attachments={path=com.hy.dubbo.api.DemoService
, interface=com.hy.dubbo.api.DemoService
, version=1.0.0}]]
所以当前的message中具有当前所有请求的信息
channel的实际类型为NettyChannel
2.9 查看NettyChannel中的send方法
@Override
public void send(Object message, boolean sent) throws RemotingException {
// 通道是否关闭
super.send(message, sent);
boolean success = true;//是否发送成功
int timeout = 0;//定义超时时间
try {
ChannelFuture future = channel.writeAndFlush(message);//开始写和发送消息
if (sent) {//判断是否已经发下哦那个
// wait timeout ms
timeout = getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);//获取超时时间
success = future.await(timeout);//通过等待的方式判断当前的任何五是否执行成功
}
Throwable cause = future.cause();
if (cause != null) {
throw cause;
}
} catch (Throwable e) {
throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
}
if (!success) {
throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress()
+ "in timeout(" + timeout + "ms) limit");
}
}
1.通过源码发现当前的NettyChannel方法是调用一个可回调的类进行执行操作
2.debug发现当前的channel.writeAndFlush(message);中的channel实际上为NettySocketChannel
3.所以当前的Customer实际上就是通过Netty对服务提供者进行发送消息的请求,然后通过回调的方式返回调用的结果
,这个具有超时时间
3.总结
1.当前的客户端获取的任何实例都是一个代理对象
,给代理对象的操作都会调用invoke方法,所有的操作都统一在invoke方法中实现(这点和MyBatis的源码相似)
2.dubbo中的代理模式使用的太多了,可能会导致源码难以看懂
3.dubbo通过异步的方式使用Netty发送消息请求
,并在1000ms
内获取的返回结果
,对于使用debug查看可能不是很友好,因为debug不止1秒的时间
,所以通常会导致结果为null,还有请求超时的异常
4.通过阅读源码发现当前的dubbo中使用了大量的代理
和java.util.concurrent.Future<V>
这个类
以上纯属个人见解,如有问题请联系本人!