dubbo客户端
来源:互联网 发布:淘宝店铺0信誉的多少钱 编辑:程序博客网 时间:2024/05/14 20:53
一概述
我们知道在spring整合dubbo以后,在spring容器中取客户端对象时通过关键字ID来获取,跟平常的取法一模一样。那么这章来分析下spring怎么把dubbo框架的客户端对象加载到spring容器中的,怎么创建接口的代理对象,然后如何调用到远程服务器的真实的接口实现。
二初始化客户端配置
Spring在初始化IOC容器,通过DubboNamespaceHandler类来解析dubbo相关标签,在解析客户端标签dubbo:reference时,标签解析出来的相关属性都是存储到ReferenceBean类中,因为ReferenceBean类实现了InitializingBean接口,所以在设置标签所有属性后会调用afterPropertiesSet方法,关于标签bean载体类实现spring框架的InitializingBean接口相关知识可以自己百度了解下,有很多写的比较好的文章,这里就不在细说。具体看afterPropertiesSet方法如下:@SuppressWarnings({ "unchecked"}) public void afterPropertiesSet() throws Exception { //判断当前ConsumerConfig是否存在,如果不存在从spring容器中取相关的ConsumerConfig对象,并设置到当前属性中 if (getConsumer() == null) { Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, false, false); if (consumerConfigMap != null && consumerConfigMap.size() > 0) { ConsumerConfig consumerConfig = null; for (ConsumerConfig config : consumerConfigMap.values()) { if (config.isDefault() == null || config.isDefault().booleanValue()) { if (consumerConfig != null) { throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config); } consumerConfig = config; } } if (consumerConfig != null) { //设置当前ConsumerConfig对象 setConsumer(consumerConfig); } } } //判断当前ApplicationConfig是否存在,不存在从spring容器中获取,并关联到当前类的属性中 if (getApplication() == null && (getConsumer() == null || getConsumer().getApplication() == null)) { Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); if (applicationConfigMap != null && applicationConfigMap.size() > 0) { ApplicationConfig applicationConfig = null; for (ApplicationConfig config : applicationConfigMap.values()) { if (config.isDefault() == null || config.isDefault().booleanValue()) { if (applicationConfig != null) { throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); } applicationConfig = config; } } if (applicationConfig != null) { //设置当前ApplicationConfig属性 setApplication(applicationConfig); } } } //判断当前ModuleConfig是否存在,不存在从spring容器中获取,并关联到当前类属性中 if (getModule() == null && (getConsumer() == null || getConsumer().getModule() == null)) { Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); if (moduleConfigMap != null && moduleConfigMap.size() > 0) { ModuleConfig moduleConfig = null; for (ModuleConfig config : moduleConfigMap.values()) { if (config.isDefault() == null || config.isDefault().booleanValue()) { if (moduleConfig != null) { throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); } moduleConfig = config; } } if (moduleConfig != null) { //设置当前ModuleConfig对象 setModule(moduleConfig); } } } //判断当前List<RegistryConfig>注册中心是否存在,如果不存在从spring容器中获取,并关联到当前类属性中 if ((getRegistries() == null || getRegistries().size() == 0) && (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().size() == 0) && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) { Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); if (registryConfigMap != null && registryConfigMap.size() > 0) { List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>(); for (RegistryConfig config : registryConfigMap.values()) { if (config.isDefault() == null || config.isDefault().booleanValue()) { registryConfigs.add(config); } } if (registryConfigs != null && registryConfigs.size() > 0) { //设置当前的注册中心 super.setRegistries(registryConfigs); } } } //判断当前MonitorConfig监控中心是否存在,如果不存在从spring容器中获取 if (getMonitor() == null && (getConsumer() == null || getConsumer().getMonitor() == null) && (getApplication() == null || getApplication().getMonitor() == null)) { Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); if (monitorConfigMap != null && monitorConfigMap.size() > 0) { MonitorConfig monitorConfig = null; for (MonitorConfig config : monitorConfigMap.values()) { if (config.isDefault() == null || config.isDefault().booleanValue()) { if (monitorConfig != null) { throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); } monitorConfig = config; } } if (monitorConfig != null) { //设置当前的监控中心 setMonitor(monitorConfig); } } } Boolean b = isInit(); if (b == null && getConsumer() != null) { b = getConsumer().isInit(); } //是否容器启动加载时,立即初始化,默认是不立刻初始化处理,可以通过在dubbo:reference标签里面配置init=true来设置 if (b != null && b.booleanValue()) { getObject(); } }这里整个方法都是在做一些的Consumer,Application,Module,Registries等标签配置信息的检测,在方法的最后有个if判断,默认Boolean b属性的值为false,表示不做初始化。如果需要立刻做初始化需要在dubbo:reference标签里面配置init=true来设置,执行getObject方法。系统默认配置是不立刻初始化处理,那么getObject方法什么时候执行呢?这里有个跟spring容器相关的知识点。因为在解析dubbo:reference标签加载ReferenceBean时,ReferenceBean类是实现了FactoryBean接口的,并重写了getObject方法,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,当根据该Bean的Id从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象。也就是说我们在使用dubbo框架获取客户端对象的时候 ,其实是执行了getObject方法返回的对象。好了我们继续看dubbo框架源中的getObject方法,这是创建接口代理对象的关键入口处
//返回在spring容器中根据id找对象 public Object getObject() throws Exception { return get(); }public synchronized T get() { if (destroyed){ throw new IllegalStateException("Already destroyed!"); } //ref为空时就开始初始化返回的对象,也就是说根据id在spring容器中拿到的对象是ref属性。 if (ref == null) { init(); } return ref; }方法加入了synchronized锁机制防止并发问题,里面判断了ref属性是否为空,为空就调用init方法初始化。所以ref应该就是最终的接口代理对象属性吧!
private void init() { //防止多次初始化 if (initialized) { return; } //设置已经初始化 initialized = true; if (interfaceName == null || interfaceName.length() == 0) { throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!"); } // 获取消费者全局配置 //检查当前ConsumerConfig 是否存在,否则新建一个 checkDefault(); appendProperties(this); //是否使用泛型接口 if (getGeneric() == null && getConsumer() != null) { //设置泛型接口 setGeneric(getConsumer().getGeneric()); } if (ProtocolUtils.isGeneric(getGeneric())) { //如果使用了泛型接口,设置泛型接口 interfaceClass = GenericService.class; } else { //否则设置设置指定的interfaceName为泛型接口 try {interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() .getContextClassLoader());} catch (ClassNotFoundException e) {throw new IllegalStateException(e.getMessage(), e);} //检测标签配置中的方法在接口中是否存在 checkInterfaceAndMethods(interfaceClass, methods); } //这块没看懂是做什么,好像是在加载什么属性配置文件 String resolve = System.getProperty(interfaceName); String resolveFile = null; if (resolve == null || resolve.length() == 0) { resolveFile = System.getProperty("dubbo.resolve.file"); if (resolveFile == null || resolveFile.length() == 0) { File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties"); if (userResolveFile.exists()) { resolveFile = userResolveFile.getAbsolutePath(); } } if (resolveFile != null && resolveFile.length() > 0) { Properties properties = new Properties(); FileInputStream fis = null; try { fis = new FileInputStream(new File(resolveFile));properties.load(fis);} catch (IOException e) {throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e);} finally { try { if(null != fis) fis.close(); } catch (IOException e) { logger.warn(e.getMessage(), e); }} resolve = properties.getProperty(interfaceName); } } if (resolve != null && resolve.length() > 0) { url = resolve; if (logger.isWarnEnabled()) { if (resolveFile != null && resolveFile.length() > 0) { logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service."); } else { logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service."); } } } //再次检测ConsumerConfig配置 if (consumer != null) { if (application == null) { application = consumer.getApplication(); } if (module == null) { module = consumer.getModule(); } if (registries == null) { registries = consumer.getRegistries(); } if (monitor == null) { monitor = consumer.getMonitor(); } } //再次检测module配置 if (module != null) { if (registries == null) { registries = module.getRegistries(); } if (monitor == null) { monitor = module.getMonitor(); } } //再次检测application配置 if (application != null) { if (registries == null) { registries = application.getRegistries(); } if (monitor == null) { monitor = application.getMonitor(); } } //检测application checkApplication(); checkStubAndMock(interfaceClass); Map<String, String> map = new HashMap<String, String>(); Map<Object, Object> attributes = new HashMap<Object, Object>(); //设置map版本,时间,进程号 等属性值 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())); //设置pid值 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); //设置application中属性值到map中 appendParameters(map, application); //设置module中属性值到map中 appendParameters(map, module); //设置consumer中属性值到map中 appendParameters(map, consumer, Constants.DEFAULT_KEY); //设置当前标签bean属性值到map中 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); } } //attributes通过系统context进行存储. StaticContext.getSystemContext().putAll(attributes); //重点地方根据map中的属性创建接口的代理对象,map中保存了application,module,consumer,reference配置信息 ref = createProxy(map); }
init总体思路就是再次检测了Consumer,Application,Module,Registries等配置信息,并将配置信息全部存入到Map中。注意最后一段代码 ref = createProxy(map); 看代码应该就能理解它的作用创建代理对象,并传入了前面存进所有参数的map属性。重点的地方来了代理是怎么创建出来的。三创建客户端invoker对象。createProxy方法详情如下
@SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })private T createProxy(Map<String, String> map) { //根据map中的属性值生成URL对象URL tmpUrl = new URL("temp", "localhost", 0, map);final boolean isJvmRefer; if (isInjvm() == null) { if (url != null && url.length() > 0) { //指定URL的情况下,不做本地引用 isJvmRefer = false; } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { //默认情况下如果本地有服务暴露,则引用本地服务. isJvmRefer = true; } else { isJvmRefer = false; } } else { isJvmRefer = isInjvm().booleanValue(); }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 { //判断当前客户端是否是点对点直连,直连会跳过注册中心 //直连或者注册连接的url都会存储在urls中 if (url != null && url.length() > 0) { // 用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL 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 { // 通过注册中心配置拼装URL 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."); } } if (urls.size() == 1) { //只有一个注册服务器时,生成客户端的代理invoker invoker = refprotocol.refer(interfaceClass, urls.get(0)); } else { //当有多个注册服务器时,生成多个客户端代理 List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); URL registryURL = null; for (URL url : urls) { //多个服务端,生成多个对应的invoker对象 invokers.add(refprotocol.refer(interfaceClass, url)); if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { registryURL = url; // 用了最后一个注册服务器作为注册中心 registry url } } if (registryURL != null) { // 有 注册中心协议的URL // 对有注册中心的集群 只用 AvailableCluster URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); invoker = cluster.join(new StaticDirectory(u, invokers)); } else { // 不是 注册中心的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()); } if (logger.isInfoEnabled()) { logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); } // 创建服务代理 return (T) proxyFactory.getProxy(invoker); }上面方法中主要做了一件事情就是创建客户端接口的invoker对象,我们重点解析这段代码 invoker = refprotocol.refer(interfaceClass, url);
refprotocol对象是什么怎么创建的,创建代码如下 Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();具体如何创建出来的后面专门通过章节来讲解, 这里我就默认refprotocol属性是DubboProtocol类了,查看该类的refer方法如下:
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException { // modified by lishen optimizeSerialization(url); // create rpc invoker. DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers); invokers.add(invoker); return invoker;}invoker对象原来就是DubboInvoker类。因为DubboInvoker继承了AbstractInvoker类,它重写了父类的doInvoke方法。在看看AbstractInvoker代码,它的invoke方法中最终还是执行了doInvoke方法,因为当前类的doInvoke是抽象的,所以最终还是执行了DubboInvoker中的doInvoke方法。按个人猜想这里的invoke应该就是处理客户端请求的入口吧!
public Result invoke(Invocation inv) throws RpcException { if(destroyed) { 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 { //执行了子类的doInvoke方法 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); } }好吧我们继续查看DubboInvoker该类的代码如下:
public class DubboInvoker<T> extends AbstractInvoker<T> {private final ExchangeClient[] clients;private final AtomicPositiveInteger index = new AtomicPositiveInteger();private final String version;private final ReentrantLock destroyLock = new ReentrantLock();private final Set<Invoker<?>> invokers;public DubboInvoker(Class<T> serviceType, URL url, ExchangeClient[] clients){this(serviceType, url, clients, null);}public DubboInvoker(Class<T> serviceType, URL url, ExchangeClient[] clients, Set<Invoker<?>> invokers){super(serviceType, url, new String[] {Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY});this.clients = clients;// get version.this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0");this.invokers = invokers; }@Overrideprotected Result doInvoke(final Invocation invocation) throws Throwable {RpcInvocation inv = (RpcInvocation) invocation;final String methodName = RpcUtils.getMethodName(invocation);inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());inv.setAttachment(Constants.VERSION_KEY, version);ExchangeClient currentClient;if (clients.length == 1) {currentClient = clients[0];} else {currentClient = clients[index.getAndIncrement() % clients.length];}try {boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);if (isOneway) {//只负责发送消息,不需要等待反馈接口,所以结果始终未NULLboolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);currentClient.send(inv, isSent);RpcContext.getContext().setFuture(null);return new RpcResult();} else if (isAsync) {//异步请求ResponseFuture future = currentClient.request(inv, timeout) ;RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));return new RpcResult();} else {//默认阻塞请求RpcContext.getContext().setFuture(null);return (Result) currentClient.request(inv, timeout).get();}} 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);}}@Overridepublic 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() {//防止client被关闭多次.在connect per jvm的情况下,client.close方法会调用计数器-1,当计数器小于等于0的情况下,才真正关闭if (super.isDestroyed()){return ;} else {//dubbo check ,避免多次关闭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();}}}}注意看doInvoke方法中的实现,从ExchangeClient clients[]数组中取出一个对象currentClient将客户端接口请求信息发送给服务端处理。注意了这里的ExchangeClient保存的是客户端与服务器建立的socket链接对象,也就是netty的客户端对象。 在发送请求处理有3个逻辑判断
1.只负责发送请求,不需要等待反馈消息
2.异步请求
3.默认是阻塞的请求
四 创建netty客户端链接对象
上面已经讲到了通过netty的客户端发消息给服务器请求,那netty客户端是怎么创建的?如果看了前面服务端的发布分析应该会很快明白!这里我们回到创建invoker对象的代码,如下:DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);看看里面调用了getClients方法。
private ExchangeClient[] getClients(URL url){ //是否共享连接 boolean service_share_connect = false; int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0); //如果connections不配置,则共享连接,否则每服务每连接 if (connections == 0){ service_share_connect = true; connections = 1; } ExchangeClient[] clients = new ExchangeClient[connections]; for (int i = 0; i < clients.length; i++) { if (service_share_connect){ //如果共享链接,那么获取共享的链接对象 clients[i] = getSharedClient(url); } else { //不共享链接,那么开启netty客户端连接对象 clients[i] = initClient(url); } } return clients; }里面有是否共享链接对象的一个逻辑判断处理,创建链接对象需跟进initClient方法的处理。
/** * 创建新连接. */ private ExchangeClient initClient(URL url) { // client type setting. String str = url.getParameter(Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_CLIENT)); String version = url.getParameter(Constants.DUBBO_VERSION_KEY); boolean compatible = (version != null && version.startsWith("1.0.")); url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() && compatible ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME); //默认开启heartbeat url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); // BIO存在严重性能问题,暂时不允许使用 if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) { throw new RpcException("Unsupported client type: " + str + "," + " supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " ")); } ExchangeClient client ; try { //设置连接应该是lazy的 if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)){ client = new LazyConnectExchangeClient(url ,requestHandler); } else { //新建一个netty客户端链接 client = Exchangers.connect(url ,requestHandler); } } catch (RemotingException e) { throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e); } return client; }看到该方法最下面的catch块代码:Exchangers.connect(url ,requestHandler);调用connect时传入了url和requestHandler两个属性,你会发现netty的客户端和服务器响应处理器都使用了相同的处理器。前面已经分析过,这里就不废话了。继续往connect方法中看。
public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { if (url == null) { throw new IllegalArgumentException("url == null"); } if (handler == null) { throw new IllegalArgumentException("handler == null"); } url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange"); return getExchanger(url).connect(url, handler); }/** * 开启netty客户端链接 * @param url * @param handler * @return * @throws RemotingException */public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))));}public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException { if (url == null) { throw new IllegalArgumentException("url == null"); } ChannelHandler handler; if (handlers == null || handlers.length == 0) { handler = new ChannelHandlerAdapter(); } else if (handlers.length == 1) { handler = handlers[0]; } else { handler = new ChannelHandlerDispatcher(handlers); } return getTransporter().connect(url, handler); }//创建netty客户端链接对象public Client connect(URL url, ChannelHandler listener) throws RemotingException { return new NettyClient(url, listener); }看看这一连串的connect方法的处理最终生成了NettyClient对象,并设置netty客户端响应处理。到这里已经一层一层剥离到netty框架层次了。熟悉netty的朋友可以继续往下看非常容易看懂dubbo的实现了。
四创建接口代理对象
终于到看到代理的处理,一路坎坷!我们回到代理的创建方法ReferenceConfig.createProxy中最后一行的代码return (T) proxyFactory.getProxy(invoker); 这里的proxyFactory属性请允许我默认当做AbstractProxyFactory类实现
public abstract class AbstractProxyFactory implements ProxyFactory {public <T> T getProxy(Invoker<T> invoker) throws RpcException {Class<?>[] interfaces = null;String config = invoker.getUrl().getParameter("interfaces");if (config != null && config.length() > 0) {String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);if (types != null && types.length > 0) {interfaces = new Class<?>[types.length + 2];interfaces[0] = invoker.getInterface();interfaces[1] = EchoService.class;for (int i = 0; i < types.length; i ++) {interfaces[i + 1] = ReflectUtils.forName(types[i]);}}}if (interfaces == null) {interfaces = new Class<?>[] {invoker.getInterface(), EchoService.class};}return getProxy(invoker, interfaces);}public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);}最后还是执行了抽象的getProxy方法。因为JavassistProxyFactory类继承了AbstractProxyFactory,并重写了getProxy方法所以最终还是执行了JavassistProxyFactory类中的getProxy方法。
@SuppressWarnings("unchecked") public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); }getProxy方法中的实现完全依靠了jdk自带的动态代理生成功能,不太清楚的可以查看下相关资料,估计一看就明白啦。到这里就已经生成了客户端接口的代理实现对象。其实可以将生成的代理对象类结构代码贴出来,能更好的帮助你理解里面的执行机制!
五 总结
如果你看玩dubbo的服务发布代码分析,估计看客户端的发布应该比较轻松。主要还是涉及到的知识点任然还是那些!不过刚开始看的时候没太理解ReferenceBean类实现FactoryBean,InitializingBean接口的机制绕了一些弯路。其它没什么想说的!下章来仔细分析下dubbo里面的SPI技术对接口的扩展,感觉这SPI应该放在最前面讲解比较好,因为源码中接口的实现对象获取跟它有很大的关系!提前讲解会比较容易理解。后面有时间把整个章节顺序调整下!
- dubbo客户端
- Dubbo服务端/客户端demo
- dubbo容器-客户端调用
- dubbo源代码分析-dubbo客户端初始化
- (八)轻松dubbo 客户端 服务器 demo + zookeeper
- dubbo搭建-客户端开发(三)
- Dubbo源码阅读之 客户端远程调用
- 短文了解系统dubbo客户端通过zk调用另一个系统的dubbo服务端
- dubbo之客户端和服务端采用zookeeper技术进行通信
- Dubbo+Spring+MyBaits客户端得到对象的属性为空
- dubbo服务端启动注册成功,客户端无法调用问题
- Dubbo源码阅读之 服务端和客户端处理链
- dubbo--远程调用数据交换层客户端类图
- 用dubbo框架写的简单的接口作为客户端
- dubbo
- Dubbo
- dubbo
- dubbo
- ubuntu 下安装KVM虚拟化
- 调整Docker时间
- JAVA enum 和 Enum 的区别
- Hdu 3966 Aragorn's Story【树链剖分模板题】模板记录
- 源码 Toast 的 window 创建过程
- dubbo客户端
- Java导出Excel的工具类
- PID的理解
- 动态规划——最长非降子序列的长度
- 敏捷开发之Scrum扫盲
- Windows系统中监控文件复制操作的几种方式
- GDB详解
- 腾讯云开放DevOps敏捷开发套件,助开发者驶入开发快车道
- JVM调优