美文网首页
Hello World及浅析dubbo通信方式

Hello World及浅析dubbo通信方式

作者: eblly | 来源:发表于2017-03-16 19:15 被阅读0次

    [TOC]

    代码

    import java.util.List;
    
    public abstract interface DemoService {
        
        public abstract String build(String name) throws Exception;
    
        String sayHello(String name);
    
        List getUsers();
    
    }
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class DemoServiceImpl implements DemoService {
        
        public String sayHello(String name) {
            return "Hello " + name;
        }
    
        public List getUsers() {
            List list = new ArrayList();
            User u1 = new User();
            u1.setName("jack");
            u1.setAge(20);
            u1.setSex("男");
    
            list.add(u1);
            return list;
        }
    
        public String build(String name) throws Exception {
            return null;
        }
    }
    
    
    import java.io.Serializable;
    
    //必须实现Serializable接口
    public class User implements Serializable {
        private static final long serialVersionUID = -2814022769568306965L;
        private String name;
        private Integer age;
        private String sex;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "User{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}';
        }
    }
    

    dubbo-provider.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://code.alibabatech.com/schema/dubbo
           http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 提供方应用信息,用于计算依赖关系 -->
        <dubbo:application name = "hello-world-app-provider" />
    
        <!--zookeeper注册中心 -->
        <dubbo:registry protocol="zookeeper" address="vimda.vimda:2181" />
    
        <!-- 用dubbo协议在20880端口暴露服务 -->
        <dubbo:protocol name="dubbo" port="20880" />
    
        <!-- 具体的实现bean -->
        <bean id="demoProvideService" class="dubboxTs.DemoServiceImpl" />
    
        <!-- 暴露的服务接口 -->
        <dubbo:service interface="dubboxTs.DemoService" ref="demoProvideService"/>
    </beans>
    
    

    bean指定id,此id可用于其他bean或者dubbo:service引用;同时指明实现类dubboxTs.DemoServiceImpl
    dubbo:service interface指定服务接口类,ref引用上述已定义的服务bean ID。
    dubbo:registry 指明通信协议和zookeeper地址。

    dubbo-consumer.xml

    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://code.alibabatech.com/schema/dubbo
           http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
        <dubbo:application name="hello-world-app-consumer"/>
            
        <!-- 使用zookeeper注册中心暴露服务地址 -->
        <dubbo:registry protocol="zookeeper" address="vimda.vimda:2181"/>
        
        <!-- 增加引用远程服务配置  -->
        <dubbo:reference id="demoConsumeService" interface="dubboxTs.DemoService"/>
    
    </beans>
    
    

    consumer先使用<
    dubbo:registry>引用zookeeper。
    其次使用dubbo:reference 引用已注册在zookeeper中心的provide(demoConsumeService),并指出demoConsumeService的实现接口。

    log4j.properties

    log4j.rootLogger=debug,A1,DRF
    
    # A1 is set to be a ConsoleAppender.
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    # A1 uses PatternLayout.
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    log4j.appender.A1.layout.ConversionPattern=[%-5p][%d{yyyyMMdd HH:mm:ss,SSS}] [THREAD ID=%t] [%C{1}:%L]  %m%n
    
    #DRF
    log4j.appender.DRF=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.DRF.Threshold=${log4j.leve}
    log4j.appender.DRF.DatePattern='.'yyyy-MM-dd
    log4j.appender.DRF.File=./log/monitor.log
    #log4j.appender.DRF.File=../log/monitor.log
    log4j.appender.DRF.Append=true
    log4j.appender.DRF.layout=org.apache.log4j.PatternLayout
    log4j.appender.DRF.layout.ConversionPattern=[%-5p][%d{yyyyMMdd HH:mm:ss,SSS}] [THREAD ID=%t] [%C{1}:%L] %m%n
    
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import dubboxTs.DemoService;
    public class ConsumerTs {
    
        @Test
        public void startConsumer() {
            try {
                String configLocation = "dubbo-consumer.xml";
                ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
                String[] names = context.getBeanDefinitionNames();
                System.out.print("Beans:");
                for (String string : names) {
                    System.out.print(string);
                    System.out.print(",");
                }
                System.out.println();
    
                DemoService ds = (DemoService) context.getBean("demoConsumeService");
                System.out.println(ds.sayHello("hehe"));
                System.out.println(ds.getUsers());
    
                Thread.sleep(Long.MAX_VALUE);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    
    
    
    import java.io.IOException;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class ProviderTs {
    
        
        @Test
        public void startProvider(){
            String configLocation = "dubbo-provider.xml";
            ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
            String[] names = context.getBeanDefinitionNames();
            System.out.print("Beans:");
            System.out.println();
            
            for (String string : names){
                System.out.print(string + ";");
            }
            
            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    先启动ProviderTs,后启动ConsumerTs
    provider控制台

    property source. Returning [null]
    Beans:
    hello-world-app-provider;com.alibaba.dubbo.config.RegistryConfig;dubbo;demoProvideService;dubboxTs.DemoService;
    

    consumer控制台

    property source. Returning [null]
    Beans:
    hello-world-app-provider;com.alibaba.dubbo.config.RegistryConfig;dubbo;demoProvideService;dubboxTs.DemoService;[DEBUG][20170115 00:41:36,583]
    

    讲解


    流程如下图所示:

    1.jpg

    节点角色说明:
    Provider: 暴露服务的服务提供方。
    Consumer: 调用远程服务的服务消费方。
    Registry: 服务注册与发现的注册中心。
    Monitor: 统计服务的调用次调和调用时间的监控中心。
    Container: 服务运行容器。

    调用关系说明:

    1. 服务容器负责启动,加载,运行服务提供者。
    2. 服务提供者在启动时,向注册中心注册自己提供的服务。
    3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
    4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
    5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
    6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

    窥看dubbo调用过程

    问题

    1. consumer如何找到消费者

    2. consumer如何调用消费者的方法

    3. provider如何接受消费者的请求和参数,并如何调用对应方法

    4. provider如何返回调用结果

    首次调用
    首先在ReferenceConfig的createProxy()等到invoker

    interface DemoService -> zookeeper://192.168.91.25:2181/com.alibaba.dubbo.registry.RegistryService?anyhost=true&application=hello-world-app-consumer&check=false&dubbo=2.5.3&interface=DemoService&methods=sayHello,build,getUsers&pid=13388&side=consumer&timestamp=1489659254215
    

    我的zookeeper IP 端口为192.168.91.25:2181.
    如下图,未执行ds.sayHello("hehe")前,消费者仍未知 提供者的具体"位置".

    2.png

    在 MockClusterInvoker处, result = this.invoker.invoke(invocation);进入AbstractClusterInvoker

    public Result invoke(Invocation invocation) throws RpcException {Result result = null;String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();if (value.length() == 0 || value.equalsIgnoreCase("false")){//no mock result = this.invoker.invoke(invocation);} else if (value.startsWith("force")) {if (logger.isWarnEnabled()) {logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());}//force:direct mock result = doMockInvoke(invocation, null);} else {//fail-mock try {result = this.invoker.invoke(invocation);}catch (RpcException e) {if (e.isBiz()) {throw e;} else {if (logger.isWarnEnabled()) {logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);}result = doMockInvoke(invocation, e);}}}return result;}
    
    

    在AbstractClusterInvoker 226行处获得invokers的ip,端口,服务.

    
    public Result invoke(final Invocation invocation) throws RpcException {
    
            checkWheatherDestoried();
    
            LoadBalance loadbalance;
            
            List<Invoker<T>> invokers = list(invocation);
            if (invokers != null && invokers.size() > 0) {
                loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
                        .getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
            } else {
                loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
            }
            RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
            return doInvoke(invocation, invokers, loadbalance);
        }
    
    
    Paste_Image.png

    227行调用远程方法并返回调用结果.

    Paste_Image.png

    provider方面

    Paste_Image.png

    参考:

    http://blog.csdn.net/a258831020/article/details/48011777


    希望你能指出文章写得不好之处,感激不尽.

    相关文章

      网友评论

          本文标题:Hello World及浅析dubbo通信方式

          本文链接:https://www.haomeiwen.com/subject/izojnttx.html