dubbo客户端

本文深入分析了 Dubbo 在 Spring 框架中的集成过程,包括客户端配置初始化、创建客户端 Invoker 对象、Netty 客户端连接及接口代理的创建流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一概述

    我们知道在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; 
		}

		@Override
		protected 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) {
					//只负责发送消息,不需要等待反馈接口,所以结果始终未NULL
					boolean 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);
			}
		}
		
		@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() {
			//防止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应该放在最前面讲解比较好,因为源码中接口的实现对象获取跟它有很大的关系!提前讲解会比较容易理解。后面有时间把整个章节顺序调整下!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值