《dubbo实战》系列导航
- 准备和初体验
- 与SpringBoot集成
- 使用Zookeeper注册中心
- 管理控制台dubbo-admin
关于dubbo
- Apache Dubbo (发音<font color="blue">ˈdʌbəʊ</font>) 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现;
- 以下是来自官方的架构图:
版本简介和选定
- 截止写此文时,Dubbo 社区主力维护的有 2.6.x 和 2.7.x 两大版本;
- 2.6.x 主要以 bugfix 和少量 enhancements 为主,因此能完全保证稳定性;
- 2.7.x 作为社区的主要开发版本,得到持续更新并增加了大量新 feature 和优化,同时也带来了一些稳定性挑战;
- 综上所述,《dubbo实战》系列选择了社区推荐的<font color="red">2.7.6</font>版本,这是2.7系列的稳定版;
环境信息
我这边用来编码的环境如下:
- 操作系统:macOS Catalina 10.15.5
- JDK:1.8.0_121
- Maven:33.3.9
- 开发工具:IntelliJ IDEA 2019.3.2 (Ultimate Edition)
注意事项
如果您是在windows环境运行代码,并且安装了VMWare,请您关闭对应的虚拟网卡,否则在广播模式(Multicast)时,consumer可能无法找到自己所需的服务;
本篇概览
- 作为《dubbo实战》系列的开篇,本文的主要内容如下:
- 创建整个《dubbo实战》系列的父工程;
- 创建整个《dubbo实战》系列的公共二方库;
- 初步体验dubbo框架,为了简单,本篇的实战暂不使用注册中心,而是服务提供方启动时广播自己的地址,再由消费方启动时订阅,并随时远程调用,调用逻辑如下图所示:
4. 先创建一个提供远程服务的子工程,名为<font color="blue">helloxmldirectprovider</font>,并运行起来; 5. 再创建名为<font color="blue">helloxmldirectconsumer</font>的子工程,运行起来后,会调用<font color="blue">helloxmldirectprovider</font>提供的远程服务,将远端返回的内容打印出来;
- 接下来开始编码
源码下载
- 如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示:
名称 | 链接 | 备注 |
---|---|---|
项目主页 | https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 |
git仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https协议 |
git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |
- 这个git项目中有多个文件夹,本章的应用在<font color="blue">dubbopractice</font>文件夹下,如下图红框所示:
3. <font color="blue">dubbopractice</font>是父子结构的工程,本篇的代码在<font color="red">helloxmldirectprovider</font>和<font color="red">helloxmldirectconsumer</font>这两个子工程中,如下图:
《dubbo实战》系列的父工程
- 为了方便管理《dubbo实战》系列的代码和依赖库版本的管理,这里创建名为<font color="blue">dubbopractice</font>的父maven工程,整个系列的后续源码都会作为它的子工程;
- dubbopractice的pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modules> <module>practiceinterface</module> <module>helloxmldirectprovider</module> <module>helloxmldirectconsumer</module> <module>springbootzkprovider</module> <module>springbootzkconsumer</module> <module>springbootmulticastprovider</module> <module>springbootmulticastconsumer</module> </modules> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <java.version>1.8</java.version> <dubbo.version>2.7.6</dubbo.version> <springboot.version>2.3.3.RELEASE</springboot.version> </properties> <modelVersion>4.0.0</modelVersion> <groupId>com.bolingcavalry</groupId> <artifactId>dubbopractice</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <dependencyManagement> <dependencies> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-bom</artifactId> <version>${dubbo.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.25.Final</version> </dependency> <!-- dubbo相关 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-multicast</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.7</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jdk8</artifactId> <version>2.11.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> <scope>compile</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.7</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.10</version> <scope>compile</scope> </dependency> <!-- swagger依赖 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.5.0</version> </dependency> <!-- swagger-ui --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.5.0</version> </dependency> </dependencies> </dependencyManagement> </project>
《dubbo实战》系列的二方库
- 涉及到多个工程之间的服务调用,因此要有个工程保存公用的数据结构、接口定义等,因此新建名为<font color="blue">practiceinterface</font>的子工程;
- <font color="blue">practiceinterface</font>工程的pom.xml内容如下,非常简单:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>dubbopractice</artifactId> <groupId>com.bolingcavalry</groupId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.bolingcavalry</groupId> <artifactId>practiceinterface</artifactId> <version>1.0-SNAPSHOT</version> <name>practiceinterface</name> <description>Beans of all app</description> </project>
- 此工程目前只有一个接口定义,后面多个子工程都会用到:
package com.bolingcavalry.dubbopractice.service; public interface DemoService { String sayHello(String name); }
编码(服务提供方)
- 先创建提供服务的工程<font color="blue">helloxmldirectprovider</font>,一共要创建6个文件,创建顺序和功能如下表:
创建顺序 | 文件名 | 作用 |
---|---|---|
1 | pom.xml | 工程的pom文件 |
2 | src/main/java/com/bolingcavalry/helloxmldirectprovider/ProviderApplication.java | 启动类 |
3 | src/main/java/com/bolingcavalry/helloxmldirectprovider/service/impl/DemoServiceImpl.java | 提供具体的服务 |
4 | src/main/resources/log4j.properties | 日志配置文件 |
5 | src/main/resources/dubbo.properties | dubbo配置文件 |
6 | src/main/resources/spring/dubbo-provider.xml | spring的bean配置 |
- 完整的文件位置如下图:
- 接下来逐个创建上述内容;
- 创建名为<font color="blue">helloxmldirectprovider</font>的子工程,pom.xml内容如下,可见刚才新建的二方库<font color="blue">practiceinterface</font>也被依赖了:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>dubbopractice</artifactId> <groupId>com.bolingcavalry</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.bolingcavalry</groupId> <artifactId>helloxmldirectprovider</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.bolingcavalry</groupId> <artifactId>practiceinterface</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> </dependencies> </project>
- 编写启动类<font color="blue">ProviderApplication.java</font>,可见就是个普通的后台程序,加载spring配置做初始化:
package com.bolingcavalry.helloxmldirectprovider; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ProviderApplication { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-provider.xml"); context.start(); System.in.read(); } }
- 编写提供具体服务的业务实现类<font color="blue">DemoServiceImpl.java</font>,只是个简单的接口实现类而已:
package com.bolingcavalry.helloxmldirectprovider.service.impl; import com.bolingcavalry.dubbopractice.service.DemoService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.rpc.RpcContext; @Slf4j public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { log.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } }
- 日志配置文件<font color="blue">log4j.properties</font>,内容如下:
###set log levels### log4j.rootLogger=info, stdout ###output to the console### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
- 在同样位置创建dubbo配置文件<font color="blue">dubbo.properties</font>,内容很简单只有qos的端口设置,用于支持telnet命令:
dubbo.application.qos.port=22222
- 在resources目录下新建文件夹<font color="blue">spring</font>,在此文件夹下创建文件<font color="blue">dubbo-provider.xml</font>,要重点关注的是<font color="blue">dubbo:registry</font>的配置,其address属性值为<font color="red">multicast://224.5.6.7:1234</font>,代表当前服务通过广播让消费者获得自身信息:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-provider"/> <!--广播模式--> <dubbo:registry address="multicast://224.5.6.7:1234" /> <bean id="demoService" class="com.bolingcavalry.helloxmldirectprovider.service.impl.DemoServiceImpl"/> <dubbo:service interface="com.bolingcavalry.dubbopractice.service.DemoService" ref="demoService"/> </beans>
- 至此,服务提供方编码完成,直接在IDEA上运行ProviderApplication类即可启动服务,启动成功后的日志输出如下图:
编码(服务消费方)
- 现在网络上已经有了服务,接下来创建一个消费该服务的工程<font color="blue">helloxmldirectconsumer</font>,一共要创建5个文件,创建顺序和功能如下表:
创建顺序 | 文件名 | 作用 |
---|---|---|
1 | pom.xml | 工程的pom文件 |
2 | src/main/java/com/bolingcavalry/helloxmldirectconsumer/ConsumerApplication.java | 启动、调用远端服务、再结束自身进程 |
3 | src/main/resources/log4j.properties | 日志配置文件 |
4 | src/main/resources/dubbo.properties | dubbo配置文件 |
5 | src/main/resources/spring/dubbo-consumer.xml | spring的bean配置 |
- 完整的文件位置如下图:
- 接下来逐个创建上述文件;
- 创建名为<font color="blue">helloxmldirectconsumer</font>的子工程,pom.xml内容如下,可见刚才新建的二方库<font color="blue">practiceinterface</font>也被依赖了:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>dubbopractice</artifactId> <groupId>com.bolingcavalry</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.bolingcavalry</groupId> <artifactId>helloxmldirectconsumer</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.bolingcavalry</groupId> <artifactId>practiceinterface</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> </dependencies> </project>
- 编写唯一的java文件<font color="blue">ConsumerApplication.java</font>,里面用了最简单的方法初始化spring环境,然后取得服务实例,执行过方法后结束进程:
package com.bolingcavalry.helloxmldirectconsumer; import com.bolingcavalry.dubbopractice.service.DemoService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ConsumerApplication { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml"); context.start(); DemoService demoService = context.getBean("demoService", DemoService.class); String hello = demoService.sayHello("world1"); System.out.println("result: " + hello); } }
- 日志配置文件<font color="blue">log4j.properties</font>,内容如下:
###set log levels### log4j.rootLogger=info, stdout ###output to console### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
- 在同样位置创建dubbo配置文件<font color="blue">dubbo.properties</font>,内容很简单只有qos的端口设置,用于支持telnet命令,本例中是用不上的,因为远程调用后进程就会结束:
dubbo.application.qos.port=33333
- 在resources目录下新建文件夹<font color="blue">spring</font>,在此文件夹下创建文件<font color="blue">dubbo-consumer.xml</font>,要重点关注的是<font color="blue">dubbo:registry</font>的配置,其address属性值为<font color="red">multicast://224.5.6.7:1234?unicast=false</font>,代表当前服务通过广播让消费者获得自身信息,<font color="blue">unicast=false</font>表示多个消费者都能收到广播:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-consumer"/> <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false"/> <dubbo:reference id="demoService" check="false" interface="com.bolingcavalry.dubbopractice.service.DemoService" timeout="2000"/> </beans>
- 上面的<font color="blue">dubbo-consumer.xml</font>中还有一处要注意,就是<font color="blue">dubbo:reference</font>的<font color="red">timeout</font>属性,这是远程调用的超时时间,此处设置为2秒,要注意的是前面<font color="blue">helloxmldirectprovider</font>提供的服务延时了1秒才返回,所以这里设置不能低于1秒;
- 至此,服务消费方编码完成,直接在IDEA上运行<font color="blue">ConsumerApplication</font>类即可启动,如下图,红框中就是远程调用helloxmldirectprovider服务返回的内容:
- 至此,《dubbo实战》系列的准备和初体验都完成了,接下来的章节,咱们会通过更多实战来学习这个优秀的框架;