Dubbo comsumer 远程调用流程分析
来源:互联网 发布:华诚律师事务所 知乎 编辑:程序博客网 时间:2024/06/12 22:02
简单代码示例:
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 --> <dubbo:application name="demo-consumer"/> <!-- 使用multicast广播注册中心暴露发现服务地址 --> <dubbo:registry address="multicast://224.5.6.7:1234"/> <!-- 生成远程服务代理,可以和本地bean一样使用demoService --> <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>
java代码:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); context.start(); DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy String hello = demoService.sayHello("world"); // call remote method System.out.println(hello); // get result
由spring配置文件,我们先看到dubbo相关定义入口NamespaceHandler:
// consumer 远程调用流程registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
init入口:
// ReferenceBean <- ReferenceConfigclass ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean { ...}
以下几个接口的比较重要:InitializingBean和FactoryBean
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法FactoryBean接口有3个方法:Object getObject():返回本工厂创建的对象实例。此实例也许是共享的,依赖于该工厂返回的是单例或者是原型,boolean isSingleton():如果FactoryBean返回的是单例,该方法返回值为true,否则为false,Class getObjectType():返回对象类型。对象类型是getObject()方法返回的对象的类型,如果不知道的类型则返回null,FactoryBean概念和接口在Spring框架中大量使用。Spring内置的有超过50个实现。
我们看看这几个重要接口方法的实现:
public Object getObject() throws Exception { return get(); } public synchronized T get() { if (destroyed) { throw new IllegalStateException("Already destroyed!"); } if (ref == null) { init(); } return ref; } private void init() { if (initialized) { return; } initialized = true; ... Map<String, String> map = new HashMap<String, String>(); Map<Object, Object> attributes = new HashMap<Object, Object>(); map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE); map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion()); map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); if (ConfigUtils.getPid() > 0) { map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); } if (!isGeneric()) { String revision = Version.getVersion(interfaceClass, version); if (revision != null && revision.length() > 0) { map.put("revision", revision); } String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); if (methods.length == 0) { logger.warn("NO method found in service interface " + interfaceClass.getName()); map.put("methods", Constants.ANY_VALUE); } else { map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ",")); } } map.put(Constants.INTERFACE_KEY, interfaceName); appendParameters(map, application); appendParameters(map, module); appendParameters(map, consumer, Constants.DEFAULT_KEY); appendParameters(map, this); // 根据服务配置获取唯一标识 String prifix = StringUtils.getServiceKey(map); if (methods != null && methods.size() > 0) { // 服务方法 for (MethodConfig method : methods) { appendParameters(map, method, method.getName()); String retryKey = method.getName() + ".retry"; if (map.containsKey(retryKey)) { String retryValue = map.remove(retryKey); if ("false".equals(retryValue)) { map.put(method.getName() + ".retries", "0"); } } appendAttributes(attributes, method, prifix + "." + method.getName()); checkAndConvertImplicitConfig(method, map, attributes); } } // 配置中心 String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); if (hostToRegistry == null || hostToRegistry.length() == 0) { hostToRegistry = NetUtils.getLocalHost(); } else if (isInvalidLocalHost(hostToRegistry)) { throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); } map.put(Constants.REGISTER_IP_KEY, hostToRegistry); //attributes通过系统context进行存储. StaticContext.getSystemContext().putAll(attributes); // 将上面的配置信息生成代理 ref = createProxy(map); ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods()); ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel); }
生成代理:
private T createProxy(Map<String, String> map) { ... if (isJvmRefer) { URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map); invoker = refprotocol.refer(interfaceClass, url); if (logger.isInfoEnabled()) { logger.info("Using injvm service " + interfaceClass.getName()); } } else { if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address. String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url); if (us != null && us.length > 0) { for (String u : us) { URL url = URL.valueOf(u); if (url.getPath() == null || url.getPath().length() == 0) { url = url.setPath(interfaceName); } if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); } else { urls.add(ClusterUtils.mergeUrl(url, map)); } } } } else { // assemble URL from register center's configuration List<URL> us = loadRegistries(false); if (us != null && us.size() > 0) { for (URL u : us) { URL monitorUrl = loadMonitor(u); if (monitorUrl != null) { map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString())); } urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); } } if (urls == null || urls.size() == 0) { throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config."); } } // 获取配置中心的获得的url,得到可执行的对象 if (urls.size() == 1) { // invoker表示远端可执行provider invoker = refprotocol.refer(interfaceClass, urls.get(0)); } else { List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); URL registryURL = null; for (URL url : urls) { invokers.add(refprotocol.refer(interfaceClass, url)); if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { registryURL = url; // use last registry url } } if (registryURL != null) { // registry url is available // use AvailableCluster only when register's cluster is available URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); invoker = cluster.join(new StaticDirectory(u, invokers)); } else { // not a registry url invoker = cluster.join(new StaticDirectory(invokers)); } } } Boolean c = check; if (c == null && consumer != null) { c = consumer.isCheck(); } if (c == null) { c = true; // default true } if (c && !invoker.isAvailable()) { throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); } // create service proxy // 生成动态代理:jdk和javassit return (T) proxyFactory.getProxy(invoker); }
invoker的invoker方法,调用rpc访问远程服务:
public Result invoke(Invocation inv) throws RpcException { if (destroyed.get()) { throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + " is DESTROYED, can not be invoked any more!"); } RpcInvocation invocation = (RpcInvocation) inv; invocation.setInvoker(this); if (attachment != null && attachment.size() > 0) { invocation.addAttachmentsIfAbsent(attachment); } Map<String, String> context = RpcContext.getContext().getAttachments(); if (context != null) { invocation.addAttachmentsIfAbsent(context); } if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) { invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString()); } RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); try { return doInvoke(invocation); } catch (InvocationTargetException e) { // biz exception Throwable te = e.getTargetException(); if (te == null) { return new RpcResult(e); } else { if (te instanceof RpcException) { ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION); } return new RpcResult(te); } } catch (RpcException e) { if (e.isBiz()) { return new RpcResult(e); } else { throw e; } } catch (Throwable e) { return new RpcResult(e); } }
thrift版本的invoker:
public class ThriftInvoker<T> extends AbstractInvoker<T> { private final ExchangeClient[] clients; private final AtomicPositiveInteger index = new AtomicPositiveInteger(); private final ReentrantLock destroyLock = new ReentrantLock(); private final Set<Invoker<?>> invokers; public ThriftInvoker(Class<T> service, URL url, ExchangeClient[] clients) { this(service, url, clients, null); } public ThriftInvoker(Class<T> type, URL url, ExchangeClient[] clients, Set<Invoker<?>> invokers) { super(type, url, new String[]{Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY}); this.clients = clients; this.invokers = invokers; } @Override protected Result doInvoke(Invocation invocation) throws Throwable { RpcInvocation inv = (RpcInvocation) invocation; final String methodName; methodName = invocation.getMethodName(); inv.setAttachment(Constants.PATH_KEY, getUrl().getPath()); // for thrift codec inv.setAttachment(ThriftCodec.PARAMETER_CLASS_NAME_GENERATOR, getUrl().getParameter( ThriftCodec.PARAMETER_CLASS_NAME_GENERATOR, DubboClassNameGenerator.NAME)); ExchangeClient currentClient; if (clients.length == 1) { currentClient = clients[0]; } else { currentClient = clients[index.getAndIncrement() % clients.length]; } try { int timeout = getUrl().getMethodParameter( methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); RpcContext.getContext().setFuture(null); return (Result) currentClient.request(inv, timeout).get(); } catch (TimeoutException e) { throw new RpcException(RpcException.TIMEOUT_EXCEPTION, e.getMessage(), e); } catch (RemotingException e) { throw new RpcException(RpcException.NETWORK_EXCEPTION, e.getMessage(), e); } } @Override public boolean isAvailable() { if (!super.isAvailable()) { return false; } for (ExchangeClient client : clients) { if (client.isConnected() && !client.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)) { //cannot write == not Available ? return true; } } return false; } public void destroy() { // in order to avoid closing a client multiple times, a counter is used in case of connection per jvm, every // time when client.close() is called, counter counts down once, and when counter reaches zero, client will be // closed. if (super.isDestroyed()) { return; } else { // double check to avoid dup close destroyLock.lock(); try { if (super.isDestroyed()) { return; } super.destroy(); if (invokers != null) { invokers.remove(this); } for (ExchangeClient client : clients) { try { client.close(); } catch (Throwable t) { logger.warn(t.getMessage(), t); } } } finally { destroyLock.unlock(); } } }}
阅读全文
0 0
- Dubbo comsumer 远程调用流程分析
- dubbo 远程服务调用流程
- Dubbo 远程同步调用原理分析
- dubbo源码浅析(五)-远程服务调用流程
- dubbo源码浅析(五)-远程服务调用流程
- 远程调用框架dubbo
- 远程调用框架dubbo
- 远程调用框架dubbo
- 远程调用框架dubbo
- dubbo 加载Bean和远程调用分析(1)
- dubbo 加载Bean和远程调用分析(1)
- dubbo 远程服务无法调用
- dubbo 动态调用分析
- 简单学习rpc -- thrift 远程调用流程简单分析
- dubbo源码分析-RPC远程调用模块与Remoting通讯模块协作细节
- dubbo 请求调用过程分析
- dubbo请求调用过程分析
- dubbo 请求调用过程分析
- lucene&solr从入门到精通-----删除,修改,查询
- php变量与变量类型
- 北上广租房记
- Redis初窥:List操作常用命令
- PyQt5笔记(05) -- 绝对位置
- Dubbo comsumer 远程调用流程分析
- 亿图图示中文破解版(附带软件破解补丁及软件破解教程)
- Hdoj 1235 统计同成绩学生人数
- 程序员修炼之道(通俗版)——第六章
- stl 容器 简略
- 数据结构实验之排序二:交换排序
- 理发师多线程实现
- ASP.net基础
- 31. Next Permutation