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,否则为falseClass 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);        }    }

invoker类型
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();            }        }    }}