先说一下dubbo调用服务的原理需要的前置步骤,相当于准备工作:
现在调用完事之后,下一步就是决定引用那种服务,有三种可供选择的嗲用服务的方式:
总的概括一下总的调用流程:
首先是ReferenceConfig类先去调用init()方法,然后会在init方法中调用Protocol的refer()方法生成一个Invoker对象实例,这里是消费服务的关键,然后会在init方法中通过createProxy(map)方法生成一个代理对象,然后在CreateProxy方法中进行判断是采用哪种调用方式(就是上面三种方式之一),并去调用refer()方法生成一个Invoker对象,接下来会把Invoker对象转换为客服端需要的对象(UserService),
1. 处理配置
2. 引用服务
DubboInvoker invoker = new DubboInvoker(serviceType, url, getClients(url), invokers);
创建的,这里走的是dubbo协议,也可能是走Injvm协议,或者是别的协议public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// 取 registry 参数值,并将其设置为协议头
url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY);
// 获取注册中心实例
Registry registry = registryFactory.getRegistry(url);
if (RegistryService.class.equals(type)) {
return proxyFactory.getInvoker((T) registry, type, url);
}
// 将 url 查询字符串转为 Map
Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
// 获取 group 配置
String group = qs.get(Constants.GROUP_KEY);
if (group != null && group.length() > 0) {
if ((Constants.COMMA_SPLIT_PATTERN.split(group)).length > 1
|| "*".equals(group)) {
// 通过 SPI 加载 MergeableCluster 实例,并调用 doRefer 继续执行服务引用逻辑
return doRefer(getMergeableCluster(), registry, type, url);
}
}
// 调用 doRefer 继续执行服务引用逻辑
return doRefer(cluster, registry, type, url);
}
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
// 创建 RegistryDirectory 实例
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
// 设置注册中心和协议
directory.setRegistry(registry);
directory.setProtocol(protocol);
Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
// 生成服务消费者链接
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters);
// 注册服务消费者,在 consumers 目录下新节点
if (!Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false)));
}
// 订阅 providers、configurators、routers 等节点数据
directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
+ "," + Constants.CONFIGURATORS_CATEGORY
+ "," + Constants.ROUTERS_CATEGORY));
// 一个注册中心可能有多个服务提供者,因此这里需要将多个服务提供者合并为一个
Invoker invoker = cluster.join(directory);
ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
return invoker;
}
然后创建Invoker成功。
创建代理,代理对象生成的入口方法为 ProxyFactory 的 getProxy,并对服务接口进行生成代理对象, Proxy 的 getProxy 方法获取 Proxy 子类,然后创建 InvokerInvocationHandler 对象,并将该对象传给 newInstance 生成 Proxy 实例
这个具体是用JDK的动态代理生成还是使用JavassistProxyFactory生成,下面是具体的实现,这个invoker和interfaces其实是在上一大步创建好的Invoker中,通过下面代码块获取到接口串,然后进行遍历切分
Class>[] interfaces = null; String config = invoker.getUrl().getParameter("interfaces");
然后把获取到的Invoker和Interfaces数组传给具体实现生成代理类的具体实现是JavassistProxyFactory还是JdkProxyFactory,然后都是通过下面的代码进行生成的,
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}