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应该放在最前面讲解比较好,因为源码中接口的实现对象获取跟它有很大的关系!提前讲解会比较容易理解。后面有时间把整个章节顺序调整下!