dubbo3种dia调用:spring(xml文件、代码配置两种)、generic泛化调用、Telnet(命令行、代码两种)、zookeeper获取服务以及服务的子级信息

1 引包
不用spring的包,用dubbo原生的包,添加包完成之后,刷新maven工程
1.1 dubbo的包

<dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>dubbo</artifactId>
 <version>2.6.5</version>
 <exclusions>
 <exclusion>
 <groupId>org.springframework</groupId>
 <artifactId>spring</artifactId>
 </exclusion>
 </exclusions>
</dependency>

1.2 zookeeper的包

<dependency>
 <groupId>com.101tec</groupId>
 <artifactId>zkclient</artifactId>
 <version>0.10</version>
 <exclusions>
 <exclusion>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 </exclusion>
 <exclusion>
 <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
 </exclusion>
 <exclusion>
 <groupId>log4j</groupId>
 <artifactId>log4j</artifactId>
 </exclusion>
 </exclusions>
</dependency>

1 dubbo是什么?
是一个分布式的服务框架——>微服务
2 dubbo能做什么
2.1 透明化的远程方法调用,调用远程方法就跟调用本地方法一样
2.2 软负载均衡及容错机制,服务集群,动态增加、减少服务器
2.3 服务自动注册与发现
3 dubbo与http的区别
3.1 http好比普通话,rpc好比团伙内部黑话
讲普通话的好处就是谁都听得懂,谁都会讲
讲黑话好处是更精简、保密、可定制;坏处就是要求client也要懂,并且大家都说一种黑话了,再换就困难了
4 为什么要用rpc
4.1 因为良好的rpc是面向服务的封装,针对服务的可用性和效率都做了优化,单纯使用http调用则缺少这些特性
4.2 http可以过防火墙,可以利用各种丰富的分析工具,http是文本协议,适合短连接,http跨网络易扩展
4.3 dubbo通讯层用的netty走socket,socket是二进制协议,安全性更高,数据有效率更高
5 socket在http的下一层
6 dubbo的架构

第一层:
							Registry			注册中心
第二层:
							Consumer		    客户端
       						Provider			服务提供者
	   						Container    		容器
第三层:
						    monitor             监控

6.1 服务提供者Provider发布一个服务后会把这个服务注册到注册中心Registry
可以在注册中心看有哪些服务(就是一个服务管理的地方)
服务行右侧的no Consumer就是还没有客户端连接到该服务上
6.2 同样一个Consumer想要消费(调用一个服务的时候),该Consumer也会注册到注册中心上,并且之间是长连接的关系
7 dubbo的配置
dubbo是采用全spring配置方式,对应用没有任何api的侵入,只需要加载dubbo的配置即可(就是引包即可),dubbo基于spring的schema扩展进行加载
7.1 schema是.xml文件中最上面的那部分,如下图:xml文件中能使用哪些标签都是通过下图中的schema定义的
在这里插入图片描述

8 举例

房产拥有者 = 服务提供者(因为他有房源)
中介 = 注册中心
买房的人 = 客户端(服务的消费方)
房产拥有者将房子挂在中介
买房的人也是去中介找房子
中介将房产拥有者与买房的人联系起来

9 注册中心
注册中心是zookeeper,也是一个中间件,用来注册服务于负载均衡的
zookeeper通过心跳机制可以检测宕机的(挂掉的、已经停止运行的)服务器,并将挂掉的服务器IP与服务对应关系从列表中删除
10 dubbo的调用
10.1 集成spring(研发人员调用dubbo接口都是采用集合spring的调用方式)
10.2 generic泛化调用
10.3 Telnet调用
作为服务的发布者都是采用第一种方式发布
作为服务的消费者可以用3种方式调用
dubbo比较难的是架构方面,不是如何调用

第一种调用(spring调用)

第一步:引jar包
提供接口应该提供什么
提供一个SDKclient给调用的人,这个SDKclient相当于一个jar包,将该SDKclient放入公司的伺服机地址,就是maven仓库
调用的人应该怎么做
要想调用别人的这个服务,就把这个jar包添加到pom文件中,与服务提供者确定好调用什么接口,以及注册中心和组(这些在注册中心中是能找到的)
第二步:创建一个xml文件
在resources文件下创建一个MyConsumer.xml文件
调用字符串参数的服务(类、接口)
Http请求是用IP+端口+路径确定唯一
dubbo是用interface+group+version确定坐标,确定唯一

<?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="dubboTest"/>
<!--连接到注册中心,zookeeper://(协议)47.105.55.243:2181注册中心地址、端口-->
<dubbo:registry address="zookeeper://47.105.55.243:2181"
               protocol="zookeeper">
<!--
id:要将该服务注册为bean,与上面自定义的dubbo的name不能一样
interface:注册中心中发布者发布的服务,就是消费者(客户端)要调用哪个服务
group:坐标,该服务的组
version:该服务的版本
timeout:超时
url:指定IP调用,正常情况下是不需要的,因为阿里云服务器将IP改了,在公司是没有这个情况的
-->
<dubbo:reference
        id="MydubboTest"
        interface="com.longteng.service.DubboTestService"
        group="longteng"
        version="1.0"
        timeout="5000"
        url="47.105.55.243:20880">
</dubbo:reference>

创建一个测试类,启动容器,调用该bean中的方法

import com.longteng.service.DubboTestService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class MySpringDubbo {
ApplicationContext context;
@BeforeClass
public void before(){
     context=new ClassPathXmlApplicationContext("MyConsumer.xml");
}

@Test
public void dubboTest(){
    //这个bean的名称就是xml中bean的id
    DubboTestService dubboTestService=(DubboTestService)context.getBean("MydubboTest");
    //调用该服务的sayHello方法
    String s=dubboTestService.sayHello("你好dubbo");
    System.out.println(s);
}
}

调用对象参数的服务

<?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="dubboTest"/>
<dubbo:registry address="zookeeper://47.105.55.243:2181"
                protocol="zookeeper">
</dubbo:registry>
<dubbo:reference
        id="MydubboUser"
        interface="com.longteng.service.UserService"
        group="longteng"
        version="1.0"
        url="47.105.55.243:20880">
</dubbo:reference>
</beans>


import com.alibaba.fastjson.JSON;
import com.longteng.domain.ResponseMessage;
import com.longteng.domain.User;
import com.longteng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class MySpringDubbo {
ApplicationContext context;
@BeforeClass
public void before(){
     context=new ClassPathXmlApplicationContext("MyConsumer.xml");
}

@Test
public void dubboUserTest(){
    UserService userService=(UserService) context.getBean("MydubboUser");
    //该User类是发布服务中决定的,不是自己工程里的User类,就是说这里的传参是发布服务者决定的
    com.longteng.domain.User user=new User();
    user.setId(1);
    ResponseMessage responseMessage=userService.getUser(user);
    //对象转json
    System.out.println(JSON.toJSONString(responseMessage));
}
}

第二种调用(generic泛化调用)

使用泛化调用,研发要做反序列化处理,很影响性能,但是作为测试调用几个是没有关系的,属于少量的调用
spring调用引入jar包的方式有局限性,所以需要泛化调用;泛化调用时不用xml文件的,不用引入依赖的,注释掉因为spring调用引入的包
1 将引入的包注释,因为泛化调用不需要引包
2 泛化调用要先知道参数类型,如果不知道的话就可以用第3中调用方式获取,接口名、参数列表、参数类型
在测试类里封装一个方法,将xml里的配置移植到该代码,与xml里的配置是相同,只是用代码体现了,xml里的配置是不灵活的,在服务启动的时候就配读取加载了,写在代码里,动态性较强

扫描二维码关注公众号,回复: 6473460 查看本文章
/**
 * GenericService是import com.alibaba.dubbo.rpc.service.GenericService;包里的,别引错包
 * GenericService:通用的服务,是一个代理接口,用于代理请求的接口,就是说要调用哪个接口是不知道的
 * 用GenericService来代理请求的接口类
 * 参数1:接口名
 * 参数2:组
 * 参数3:版本
 */
public GenericService dubboClient(String interfaceName,String group,String version){
    /**
     * ApplicationConfig是import com.alibaba.dubbo.config.ApplicationConfig;的包,别引错包
     * setName:自定义应用名
     * RegistryConfig是import com.alibaba.dubbo.config.RegistryConfig;的包,别引错包
     * setAddress就是连接到注册中
     */
    ApplicationConfig applicationConfig=new ApplicationConfig();
    applicationConfig.setName("dubboConsumer");
    RegistryConfig registryConfig=new RegistryConfig();
    //设置接口信息,配置一个泛型,预期是代理类型GenericService
    ReferenceConfig<GenericService> referenceConfig =new ReferenceConfig<GenericService>();
    //配置自定义的应用中心名称实例
    referenceConfig.setApplication(applicationConfig);
    //配置连接自定义应用中心的地址实例
    referenceConfig.setRegistry(registryConfig);
    //添加接口名称,参数为本方法的参数1
    referenceConfig.setInterface(interfaceName);
    //声明为泛化调用
    referenceConfig.setGeneric(true);
    //添加组,本方法的参数2
    referenceConfig.setGroup(group);
    //添加版本,本方法的参数3
    referenceConfig.setVersion(version);
    //这个不是必须的,因为阿里云服务器变IP的原因
    referenceConfig.setUrl("dubbo://47.105.55.243:20880");
    //相当于(GenericService)context.getBean(referenceConfig);就相当于getBean
    return referenceConfig.get();
}

测试类,调用上面的方法,发起调用(参数是对象类型)

@Test
public void userServiceGenericTest(){
    /**
     * 调用上面封装的方法,传入对应参数
     * 参数1:调用的服务(接口名或者类名)
     * 参数2:组
     * 参数3:版本
     * 调用之前获取到参数GenericService
     */
    GenericService genericService=dubboClient
                    ("com.longteng.service.UserService",
                    "longteng" ,
                    "1.0" );
    //String类型的数组,用于下面真正执行的参数2
    //com.longteng.domain.User是要调用的方法的入参类型,这个是自定义类型
     //如果是多个参数那么new String的长度就根据实际参数个数填写,paramterTypes[1]="第二个参数的参数类型"例如:com.longteng.domain.String,底下的new Object[1]的长度也是根据实际长度写,第二个参数就是args[1]="第二个参数"
    String[] paramterTypes=new String[1];
    paramterTypes[0]="com.longteng.domain.User";
    //在Java里任何自定义对象都可以使用Map代替
    //Object类型的数组,用于下面真正执行的参数3
    Map map=new HashMap();
    map.put("id",1 );
    Object [] args=new Object[1];
    args[0]=map;
      /**
     * 真正执行调用,有3个参数
     * 参数1:要调用的方法名称
     * 参数2:调用方法的参数类型
     * 参数3:调用方法需要传的参数
     */
    Object returnObject=genericService.$invoke("getUser",paramterTypes ,args );
    System.out.println(returnObject);
}

调用String类型的参数

   @Test
   public void dubboTestServiceGenericTest(){
    /**
     * 调用上面封装的dubboClient方法,传入3个参数
     * 参数1:服务名
     * 参数2:组
     * 参数3:版本
     */
    
    GenericService genericService=dubboClient
            ("com.longteng.service.DubboTestService",
                    "longteng",
                    "1.0");
    //调用的方法只有一个参数,是String类型,传入的参数是hello dubbo
    String[] parameterTypes=new String[1];
    parameterTypes[0]="java.lang.String";
    Object []args=new Object[1];
    args[0]="hello dubbo";
    //执行调用,参数1:方法名;参数2:参数类型;参数3:参数
    Object  returnObject=genericService.$invoke("sayHello",parameterTypes , args);
    System.out.println(returnObject);
}

第三种调用:Telnet调用

用Telnet查看服务器上发布了哪些接口
cmd命令行
如果执行连接服务提示:不是内部命令
控制面板——所有控制面板项(切换成大图标就能看到)——程序和功能——打开或关闭Windows功能——勾选Telnet客户端
Telnet服务器IP地址+端口 连接到dubbo服务上
例:

telnet 47.105.55.243 20880     连接到dubbo服务
ls   显示服务列表
ls -l 显示服务详细信息列表
ls  XxxService   显示服务的方法列表
ls -l  XxxService   显示服务方法列表的详细信息:可以看到方法的具体入参类型,返回类型

调用方法
Invoke
invoke XxxService.xxxMethed({“prop”:“value”})
XxxService:调用的服务名(接口名、类名)
xxxMethed:调用的方法名
{“prop”:“value”}:调用的参数,只能传json,如果入参是一个引用类型(对象)则要把对象转为json,多个参数用逗号隔开
例:

invoke com.longteng.Service.UserService.getUser({"id":1})
invike com.longteng.Service.DubboTestService,sayHello("hello dubbo")

telnet用代码如何调用
要使用Telnet Scoket调用 创建一个TelnetScoket类,该类在资料文件里有
该方式实现的是短链接,意味着每次只能创建一个请求,执行第二个请求telnetSocket.send结果为Socket is closed
测试类

@Test
public void telnetTest(){
    try {
   	//创建TelnetScoket实例,连接服务,相当于在命令行执行telnet 47.105.55.243 20880
        TelnetSocket telnetSocket=new TelnetSocket("47.105.55.243",20880);
        //设置调用后的返回为GBK编码,不然返回时乱码
        telnetSocket.setReadEncoding("GBK");
        //map入参转json
        Map map=new HashMap();
        map.put("id",1 );
        String param=JSON.toJSONString(map);
        String cmd="invoke com.longteng.service.UserService.getUser("+param+")";
        String result=telnetSocket.send(cmd);
        System.out.println(result);
    } catch (IOException e) {
        e.printStackTrace();
    }
}


@Test
public void telnetTest(){
    try {
        TelnetSocket telnetSocket=new TelnetSocket("47.105.55.243",20880);
        telnetSocket.setReadEncoding("GBK");
        //与在命令行执行命令是一样的
        String s=telnetSocket.send("ls -l com.longteng.service.UserService");
        System.out.println(s);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

zookeeper获取注册中心上有哪些服务、服务的IP、端口…

@Test
public void zk(){
    //是import org.I0Itec.zkclient.ZkClient;包里的,别引错包
    ZkClient zkClient=new ZkClient("47.105.55.243:2181");
    //要获取的是zookeeper注册中上com.longteng.service.DubboTestService接口的信息(IP、端口、方法、group和version),用循环获取
    List<String> dubboList =zkClient.getChildren("/dubbo/com.longteng.service.DubboTestService/providers");
    for(String s:dubboList){
        try {
            String url= URLDecoder.decode(s,"UTF-8" );
            System.out.println(url);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

这样就清晰明了了
1 用ZkClient 获取注册zookeeper上服务的IP、端口、方法、group和version(因为Telnet调用要有服务的IP、端口)
2 用Telnet获取服务拥有的方法、入参列表、入参类型(因为泛化调用需要这些信息才能调用成功)
一层层递进

猜你喜欢

转载自blog.csdn.net/qq_41767337/article/details/89421581