32 简单了解下dubbo的流程

前言

这两周周末的时候, “闲来无事”, 走了一下 dubbo 的一个简单的流程, 然后 跟了一下代码

还有很多的细节值得推敲的地方, 就留在以后了, 这里先简单的过一下整个流程

以下内容, 可能有些地方废话比较多[一些上下文的初始化 等等], 着重看一下图中标记部分 的流程以下, 其实感觉就差不多了

环境介绍一下 : spring : 4.2.5.RELEASE + dubbo : 2.5.3

dubbo 注册服务

BeanDefinitionParserDelegate. parseCustomElement(Element ele, BeanDefinition containingBd)
从 http://code.alibabatech.com/schema/dubbo 中解析出来的 namespaceHandler 是 DubboNamespaceHandler
处理 dubbo.xml 中的相关节点的是 DubboBeanDefinitionParser
首先生成id, 优先级, id, name, interface, beanClazz.getName, 然后尝试加上索引避免重复
ProtocolConfig[解析protocol], ServiceBean[如果是暴露的是class, 解析该bean], ProviderConfig[解析嵌套的provider, params], ConsumerConfig[解析嵌套的 consumer, params] 部分需要特别处理的部分, 特别处理
然后遍历方法找getter, setter, 尝试从对应的标签中解析数据[注意 : 先找的属性, 然后 才来找的xml中的数据][parameters, methods, arguments], 解析字符串类型的参数[registry, provider, protocol 逗号分隔的多个特别处理]吗, 还有一些兼容老版本的处理, onthrow, ref 等属性的处理
然后解析当前节点的所有属性, 放在parameters 里面

然后在 spring 容器, 实例化 dubbo:service 对应的 ServiceBean 的之后, afterPropertiesSet, onApplicationEvent
afterPropertiesSet : 1. provider处理, 如果当前ServiceBean没有 Provider, 如果没有 ProtoclConfig, 并且providerConfig不止一个, 过滤掉不属于默认的ProviderConfig
否则, 抓最后一个 默认ProviderConfig 配置为ProviderConfig
2. 如果没有配置 application, 则从容器中抓最后一个默认的 ApplicationConfig
3. 配置 module 的默认值, 和上面差不多
4. 配置 registryConfigs, monistorConfig, protocolConfig, path
如果不延迟发布, 则发布服务
onApplicationEvent : 如果是容器初始化完毕的事件 ContextRefreshedEvent, 并且还没有发布服务, 则发布服务

发布服务, 同步方法, 确保发布一次, 如果需要延迟发布, 起一条线程延迟发布
配置备选的application, module, registeries, monitor, protocols[如果没有原属性, 则优先 provider, module, application]
dubbo中 各个角色, 应该是application -> module -> provider -> service, 这样的一对多的关系
检查接口, 以及对应的方法是否存在, 检查引用是否存在
添加Local 标记, 打桩标记, 以及解析对应的 class
如果application为null, 创建一个空的, 并尝试初始化 取dubbo.servcice[XXXConfig, XXXBean] [+ beanId] + fiedName[优先取 System.properties, 然盘后再尝试去dubbo的配置文件], 配置 dubbo.service.shutdown.wait, dubbo.service.shutdown.wait.seconds
如果registries为空, 尝试从dubbo配置文件中拿数据, 并尝试初始化[dubbo.registry]
如果protocol为空, 则创建一个protocol, 并尝试初始化[dubbo.registry]
尝试从 dubbo 配置文件中读取数据, 初始化 service[dubbo.service]
加载对应的 LocalClazz, StubClazz, MockClazz
加载需要注册的地址, [优先系统配置, 然后是当前RegisterConfig], 提取 ApplicationConfig, ServiceConfig 中的参数[优先获取 key, default.key, getter方法的返回结果], 以及加载 getParameters 方法的返回结果
然后根据注册地址, 接口, 以及上面解析的参数, 收集注册地址
然后 遍历 ProtocolConfig, 根据协议暴露服务[开放服务器, 向zookeeper注册provider 等等]

暴露服务, 取host[如果是本地环路ip, 替换为任意主机], port[service, provider, default, randomPort],

如果一个注册中心暴露了多个服务, 则部分属性会以最后一个配置为准[heartbeat, heartbeat.timeout, accepts, idle.timeout, threads], 参数累加[resetUrl]
组装参数, 从application, module, provider, protocolConfig, service 中提取参数[规则 和上面相同[优先获取 key, default.key, getter方法的返回结果]]
遍历当前ServiceConfig的 所有methodConfig, 二级遍历所有的 ArgConfig, 从对应的Class 中查询给定的 method, 校验以及 添加参数[符合 dubbo:arguements的约定, type 或者index]
初始化部分上下文参数, generic, methods, version, token; contextPath 默认取 zookeeper 根路径
如果需要暴露服务, 如果需要在local暴露服务, 在127.0.0.1:0上面暴露服务 [创建 invoker, 封装invoker[ProtocolFilterWrapper.export]]
遍历registryUrls, 暴露服务 [创建 invoker, 封装invoker[ProtocolFilterWrapper.export]]
serviceKey : s e r v i c e G r o u p / serviceGroup/ serviceGroup/serviceName:KaTeX parse error: Undefined control sequence: \[ at position 30: …y 服务器, 开放端口, 监听\̲[̲如果有多个 ServiceCo…Adpative
NettyTransporter. bind, 暴露的相关信息 由protocol配置
上面的这一系列的流程, 涉及到了 新增的运行时根据java代码生成字节码并加载[使用Javassist 或者jdk1.6新增的javax.tools.JavaCompiler]
向zookeeper 注册provider

RegistryProtocol. export

dubbo 服务的消费

我们消费的 service, 在spring 容器中, 为我们创建的是一个 ReferenceBean 的一个 FactoryBean
afterPropertiesSet 配置 consumer, application, module, register, monitor 等等, 如果需要初始化, 则初始化
继承配置 application, consumer, register, monitor, [consumer -> module -> application], 获取所有的属性[application, module, consumer, service], 然后创建代理
根据接口, 以及url, ProtocolFilterWrapper创建 invoker[FilterChain + DubboInvoker][这部分内容参见 : ProtocolFilterWrapper.export, ProtocolFilterWrapper. refer], 创建代理, 将业务委托给 InvokerInvocationHandler[RpcInvocation 的封装]
MockClusterInvoker.invoke, AbstractClusterInvoker.invoke, FailoverClusterInvoker.doInvoke[重试], 责任链Filter, DubboInvoker. invoke
然后 ExchangeClient 发送数据传递到对应的服务提供者

DubbhhoCodec. encodeRequestData, DecodeableRpcInvocation. decode, 对应于 RpcInvocation 的编码解码的过程

HeaderExchangeChannel. request

dubbo 服务的提供

NettyCodecAdapter. InternalDecoder 拿到传过来的二进制数据之后, 进行解码, 使用DubboCountCodec 来解析对应的 RpcInvocation
到达 AllChannelHandler, 参数 和当前上下文的一些数据封装成一个Event, 创建ChannelEventRunnable, 抛入线程池执行
DubboProtocol$1. reply, 通过invocation, client的相关信息, 获取invoker,
invoker调用, 首先经过一系列的 filter, 最后调用ServceImpl 对应的代理的wrapper的doInvoke, 调用实际额的 ServiceImpl的业务方法
然后 回到 HeaderExchangeHandler 的后面, 封装 RpcResult 返回, 正常 或者异常
然后 channel.send(response), 想消费者会写数据, 关闭相关资源什么的

AllChannelHandler. received

DubboProtocol$1. reply

其他

多个 registry, 优先消费第一个 registry, ReferenceConfig : cluster.join
ZookeeperRegistry : 第一次从zookeeper拿提供者URL, zkClient.addChildListener, 之后的是由 zookeeper 通知过来
提供者向 registry 注册, ZookeeperRegistry. doRegister
ResponseFuture 的实现, await, 直到provider响应了 结果, HeaderExchangeHandler. received, 然后通知 ResponseFuture

有一些特性, 还需要之后逐步了解下override 特性, mock 特性, exportLocal 等等

还有一些网络通信相关的, 还需要加强了解下

附 : 部分运行时生成的代码

---------------------------------------------------------------

代码流程中的一些运行时创建代码, 运行时编译, 加载的类

  1. XXX$Adapative 为对应的类型的适配器, 适配器根据类型选择合理的类型实例处理业务
  2. Wrapper$id 在提供者端 和消费者端, 各个Service接口有一个, 提供者端各个Service实现有一个

1. Protocol$Adpative : ServiceConfig:507, ReferenceConfig:392

根据具体的协议 获取对应的 Protocol 的详细步骤, 可以参见 ExtensionLoader. getExtension(String name), 读取读取给定的type的配置文件[参见 ExtensionLoader:591-593]获取协议映射, 创建实例, 注入属性等等

package com.alibaba.dubbo.rpc;

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


public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
	public void destroy() {
		throw new UnsupportedOperationException(
			"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
	}

	public int getDefaultPort() {
		throw new UnsupportedOperationException(
			"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
	}

	public com.alibaba.dubbo.rpc.Exporter export(
		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.getProtocol() == null) ? "dubbo"
													  : url.getProtocol());

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

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

		return extension.export(arg0);
	}

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

		com.alibaba.dubbo.common.URL url = arg1;
		String extName = ((url.getProtocol() == null) ? "dubbo"
													  : url.getProtocol());

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

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

		return extension.refer(arg0, arg1);
	}
}

2. Wrapper1 : ServiceConfig:426; ReferenceConfig:269; JavassistProxyFactory:40

public class Wrapper1 extends com.alibaba.dubbo.common.bytecode.Wrapper {
	public static String[] pns;
	public static java.util.Map pts;
	public static String[] mns;
	public static String[] dmns;
	public static Class[] mts0;
	public static Class[] mts1;

	public String[] getPropertyNames() {
		return pns;
	}

	public boolean hasProperty(String n) {
		return pts.containsKey($1);
	}

	public Class getPropertyType(String n) {
		return (Class) pts.get($1);
	}

	public String[] getMethodNames() {
		return mns;
	}

	public String[] getDeclaredMethodNames() {
		return dmns;
	}

	public void setPropertyValue(Object o, String n, Object v) {getMethodNames
		com.hx.helloDubbo.service.impl.UserServiceImpl02 w;

		try {
			w = ((com.hx.helloDubbo.service.impl.UserServiceImpl02) $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 com.hx.helloDubbo.service.impl.UserServiceImpl02.");
	}

	public Object getPropertyValue(Object o, String n) {
		com.hx.helloDubbo.service.impl.UserServiceImpl02 w;

		try {
			w = ((com.hx.helloDubbo.service.impl.UserServiceImpl02) $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 com.hx.helloDubbo.service.impl.UserServiceImpl02.");
	}

	public Object invokeMethod(Object o, String n, Class[] p, Object[] v)
		throws java.lang.reflect.InvocationTargetException {
		com.hx.helloDubbo.service.impl.UserServiceImpl02 w;

		try {
			w = ((com.hx.helloDubbo.service.impl.UserServiceImpl02) $1);
		} catch (Throwable e) {
			throw new IllegalArgumentException(e);
		}

		try {
			if ("hello".equals($2) && ($3.length == 1)) {
				return ($w) w.hello((com.hx.helloDubbo.bean.User) $4[0]);
			}

			if ("addFriends".equals($2) && ($3.length == 2)) {
				return ($w) w.addFriends((com.hx.helloDubbo.bean.User) $4[0],
					(java.lang.String) $4[1]);
			}
		} catch (Throwable e) {
			throw new java.lang.reflect.InvocationTargetException(e);
		}

		throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException(
			"Not found method "" + $2 +
			"" in class com.hx.helloDubbo.service.impl.UserServiceImpl02.");
	}
}

3.Transporter$Adpative : Transporters. getTransporter

package com.alibaba.dubbo.remoting;

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


public class Transporter$Adpative implements com.alibaba.dubbo.remoting.Transporter {
	public com.alibaba.dubbo.remoting.Server bind(
		com.alibaba.dubbo.common.URL arg0,
		com.alibaba.dubbo.remoting.ChannelHandler arg1)
		throws com.alibaba.dubbo.common.URL {
		if (arg0 == null) {
			throw new IllegalArgumentException("url == null");
		}

		com.alibaba.dubbo.common.URL url = arg0;
		String extName = url.getParameter("server",
				url.getParameter("transporter", "netty"));

		if (extName == null) {
			throw new IllegalStateException(
				"Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" +
				url.toString() + ") use keys([server, transporter])");
		}

		com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.Transporter.class)
																												   .getExtension(extName);

		return extension.bind(arg0, arg1);
	}

	public com.alibaba.dubbo.remoting.Client connect(
		com.alibaba.dubbo.common.URL arg0,
		com.alibaba.dubbo.remoting.ChannelHandler arg1)
		throws com.alibaba.dubbo.common.URL {
		if (arg0 == null) {
			throw new IllegalArgumentException("url == null");
		}

		com.alibaba.dubbo.common.URL url = arg0;
		String extName = url.getParameter("client",
				url.getParameter("transporter", "netty"));

		if (extName == null) {
			throw new IllegalStateException(
				"Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" +
				url.toString() + ") use keys([client, transporter])");
		}

		com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.Transporter.class)
																												   .getExtension(extName);

		return extension.connect(arg0, arg1);
	}
}

# 以下ProxyFactory$Adpative, proxy0, Proxy0 新增于 2018.11.10

4.ProxyFactory$Adpative : ServiceConfig:508; ServiceConfig:426

package com.alibaba.dubbo.rpc;

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

public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory {
    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);
    }

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

5.proxy0 : JavassistProxyFactory:35

package com.alibaba.dubbo.common.bytecode;

public class proxy0 implements com.hx.helloDubbo.service.UserService, com.alibaba.dubbo.rpc.service.EchoService, com.alibaba.dubbo.common.bytecode.ClassGenerator$DC {

	public static java.lang.reflect.Method[] methods;
	private InvocationHandler handler;
	
	public proxy0() {
	}
	
	public proxy0(InvocationHandler handler) {
		this.handler = handler;
	}
	
	public java.lang.String com.hx.helloDubbo.service.UserService.hello(com.hx.helloDubbo.bean.User) {
		Object[] args = new Object[1]; 
		args[0] = ($w)$1; 
		Object ret = handler.invoke(this, methods[1], args); 
		return (java.lang.String)ret;
	}

	public com.hx.helloDubbo.bean.User com.hx.helloDubbo.service.UserService.addFriends(com.hx.helloDubbo.bean.User,java.lang.String) {
		Object[] args = new Object[2]; 
		args[0] = ($w)$1; 
		args[1] = ($w)$2; 
		Object ret = handler.invoke(this, methods[0], args); 
		return (com.hx.helloDubbo.bean.User)ret;
	}

	public java.lang.Object com.alibaba.dubbo.rpc.service.EchoService.$echo(java.lang.Object) {
		Object[] args = new Object[1]; 
		args[0] = ($w)$1; 
		Object ret = handler.invoke(this, methods[2], args); 
		return (java.lang.Object)ret;
	}
	
}

6.Proxy0 :JavassistProxyFactory:35

package com.alibaba.dubbo.common.bytecode;

public class Proxy0 extends com.alibaba.dubbo.common.bytecode.Proxy implements com.alibaba.dubbo.common.bytecode.ClassGenerator$DC {

	public Proxy0() {
	}

	public Object newInstance(java.lang.reflect.InvocationHandler h) { 
		return new com.alibaba.dubbo.common.bytecode.proxy0($1); 
	}
	
}

======================= add at 2018.01.28 =======================

刚刚偶然看见了一系列的文章, 感觉作者还是蛮用心的, 感谢分享

https://www.jianshu.com/p/8e007012367e

参考

http://shiyanjun.cn/archives/325.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值