前言
前几篇文章,简单地介绍了一下Docker的基本命令,几个比较基本但是也是比较重要的几个概念,还是希望大家能快速的上手Docker,然后又做了一个spring boot 2.1.8版 的hello Demo整合到Docker,我们编写了Dockerfile,通过了Dockerfile生成了Docker的镜像,然后运行成了容器
今天,我们开始正式的整合内容,首先从我们最常用的RPC Dubbo来入手,现在Dubbo已经重新焕发了青春,已经被Apache列为了顶级项目,未来又是一片光明
在如今,RPC框架盛行,spring Cloud家族对这块领域更是虎视眈眈,各大公司都有自己成熟的RPC框架,但是如果说经典,还是Dubbo,毕竟 在当年解决我们问题的还是Dubbo,,当年我们没有spring cloud 没有motan 没有sofa-RPC没有GPRC,RPCX等现在也算比较流行的框架 ,而在前几年Dubbo停止维护,它渐渐地脱离了我们的视野,后来大家技术不断进步,基础越来越扎实,随着大家对Netty Zookeeper的掌握理解,写一套能用的RPC框架也不在是高不可攀的事情。
现在Dubbo回归了,捐献给了apache,更新到了2.7,并有了一些新的变化,简单地列举一些,我们以后会一一一起学习
1.有了新的Dubbo Admin UI 新的管理控制台能力更加齐全,服务治理能力也变得更加完善
2.开始支持Netty4.x 数据传输模型做了新的支持
3.序列化方式做了多样化支持
4.注册中心支持Nacos ,Nacos新的配置中心和注册中心
5异步编程的API更加强大
6.开始无缝支持Spring4+ spring Boot
7.新的简化配置和新的简化注解配置
8.服务统计,链路追踪
上述的一些特性,我们逐一介绍,并了解其原理,在了解这些原理之后,我们也会实现一套自己的RPC框架
废话不多说多少,我们现在开始从头整起来,本小节首先先整理,Dubbo2.7和Spring boot2.1.8版本的整合,可能代码量相对前几个小节多一点,希望大家PC端查看
一.搭建基本效果
![f713d0dfa7b92d3b8fba8d999d02b9c0.png](https://i-blog.csdnimg.cn/blog_migrate/f0bf6c971f630126acd0d7797101a690.jpeg)
我们最后形成的基本架构图是如上图所示,这是一个景点的RPC调用方式,最后我们通过浏览器来访问,证实整个链路的连贯性和正确性
二.使用docker搭建本地单机zookeeper
大家都知道dubbo在以前是使用zookeeper做注册中心的,工欲善其事必先利其器,所以我们首先要搭建本地的zookeeper,方便我们本地的调试,使用docker搭建zk,只需要2分钟
1.1 首先查看本地已有的docker镜像,发现本地并没有zookeeper镜像
![7f69f4dac86a28795cd9e356327cb153.png](https://i-blog.csdnimg.cn/blog_migrate/cfa07c0d5b4ab196fa73fe66f3796ce4.jpeg)
1.2 首先使用【docker pull zookeeper】命令从docker的官方仓库拉去镜像,就像maven从中心仓库拉去jar包一样简单
![48fc7291668f4b1a62d2b7c936fe2f9f.png](https://i-blog.csdnimg.cn/blog_migrate/22da1457f5953ab621f8abcef9e015b2.jpeg)
1.3 最后使用【docker run -d --name zookeeper -p 2181:2181 zookeeper:latest】命令来使用docker来运行本地的单机zookeeper,-d 表示后台调用,--name 来给zookeeper这个container起一个名字,-p 2181:2181 使用端口映射的方式,可以使得本机能够访问容器中的zookeeper
![32b9276c8416fbcb6acacd626d12a6e5.png](https://i-blog.csdnimg.cn/blog_migrate/47f5aa1ebc510b9d69c7682c4a6fb5a5.jpeg)
![94518a9a8f88a201a559f9a83aa39993.png](https://i-blog.csdnimg.cn/blog_migrate/0dc6007eb691de67fe10af3969703e6f.jpeg)
二.使用IDEA搭建spring boot 2.x整合Dubbo2.7的骨架
2.1 点击create New Project,选择maven点击Next
![72441930237f188475df3007b349e850.png](https://i-blog.csdnimg.cn/blog_migrate/4c33075829607bf3a57c75041c6713eb.jpeg)
2.2 填写自定义的groupId和artifactId,点击Next,最后确认项目名,点击Next
![d74196fbb1d405e74e85fd847e725b69.png](https://i-blog.csdnimg.cn/blog_migrate/36f691f3a81e552a33d905c7ca2a4ed5.jpeg)
然后确认项目存放的地址和项目的正确名称,就可以finish
![09c984b24324385fc53027c1c7ac7f6c.png](https://i-blog.csdnimg.cn/blog_migrate/58859faaac431223c65a35a90541a819.jpeg)
2.3 创建完整个项目的结构如下,在pom.xml 增加plugins,使用jdk1.8编译整个项目,并且指定整个项目的spring-boot-parent
![9201b430eda3006360fa36258a3eef50.png](https://i-blog.csdnimg.cn/blog_migrate/d3a9d4af86b8131193d63bb3cd3c6e1c.jpeg)
部分pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>4.0.0org.lyn.bazinga dubbo-spring-boot-skeleton 1.0.01.82.1.8.RELEASEorg.springframework.boot spring-boot-starter-parent ${spring-boot-version}importpomorg.apache.maven.plugins maven-compiler-plugin 3.31.81.8UTF-8
2.4 接下来我们创建服务提供者的接口层,右击dubbo-spring-boot-skeleton,选择New,然后选择Module,同创建构架工程一样,选择Maven,点击Next
![fe871feab8a7330194b8da3ad7a2109e.png](https://i-blog.csdnimg.cn/blog_migrate/c923fe70e8a1db4d2b64b99af2397293.jpeg)
与创建父工程一样,依旧选择maven,点击Next
![57cc8fae7e72bff3cdef6a58ef5009f1.png](https://i-blog.csdnimg.cn/blog_migrate/4b94c49edfb8005f45d2f471c404ccf9.jpeg)
我们先创立dubbo的服务提供者模块,模块名叫做dubbo-spring-boot-provider,因为你创建的是Module,所以你的parent和groupId是无法编辑的,你填写一个有意义的artifactId,因为我们是提供者所以命名中有"provider",点击Next
![c6e326755b7520427a8ec261e81aeaa2.png](https://i-blog.csdnimg.cn/blog_migrate/c67b9c633a8f8ff55c5ddacab9c7e0f2.jpeg)
最后确认好你的模块名,项目所在系统路径,点击Finish之后,整个项目结构变成了如下图所示
![1f8b4db13f1036dbb5284969c69678bc.png](https://i-blog.csdnimg.cn/blog_migrate/86ff01bb9eea7d25333eb0ef91cf52c1.jpeg)
整个项目的骨架图如下图所示
![c5d02664ba825105c6eef33ad3c522eb.png](https://i-blog.csdnimg.cn/blog_migrate/06f7476c4f06280013dbbfdd61079996.jpeg)
同理,我们也新建好我们的dubbo消费者模块,操作方式也跟上面创建服务提供者的方式一样,建立好的模块图也就变成了这样
![df263025c7cfa3f691d872c24d1b0433.png](https://i-blog.csdnimg.cn/blog_migrate/4a2371562372c234f550a436d97f28b4.jpeg)
到此为止,我们已经搭建好了我们项目的基本骨架,现在就需要开始思考,因为dubbo是面向接口的,服务提供者提供接口的jar,然后服务的消费者只依赖该接口,但是并没有实现,就可以完整整个调用,所以我们这边应该还有一个最基础的模块API模块,我们刚才创建的provider和consumer都需要依赖这个模块,不过provider是这个api接口的具体实现,consumer只是依赖这个接口的jar包,创建这个api模块也跟上面创建provider和consumer一样,最后创建结束的效果骨架图如下所示,哈哈,目前为止还是非常简单的
![d7b8d4c578801644a7bd18c5c4ab1e1a.png](https://i-blog.csdnimg.cn/blog_migrate/a920e02a97c57b3d7d0abffc1f39f455.jpeg)
我们在dubbo-spring-boot-api模块新建包然后创建一个简单的接口定义
![3a185ded66205854be49ef49603e2280.png](https://i-blog.csdnimg.cn/blog_migrate/81cce204ad7f1f8822d9ac453264df0c.jpeg)
正如我们上面所说, 因为dubbo是基于接口编程的,我们的dubbo-spring-boot-api 在真实环境下会被打成jar包上传到公司的本地私有仓库,然后服务消费者会引用该jar包,然后就可以在dubbo的支持下,实现调用远程接口就像调用本地一样的效果了,所以服务提供者模块实现HelloService接口的具体业务实现 ,接下来我们完整服务提供者端完整的代码书写
3.1 dubbo-spring-boot-provider中的pom.xml的几个关键配置
3.1.1 首先在pom.xml 增加spring boot的plugin,这样在使用java -jar的时候,能够找到spring boot的main函数
org.springframework.boot spring-boot-maven-plugin 2.1.8.RELEASEpackagerepackagetrue
3.1.2 我们引入spring-boot的基本依赖
org.springframework.boot spring-boot-starter ${spring-boot-version}org.springframework.boot spring-boot-starter-web ${spring-boot-version}org.springframework.boot spring-boot-autoconfigure ${spring-boot-version}org.springframework.boot spring-boot-starter-actuator ${spring-boot-version}
3.1.3 我们需要引入dubbo-spring-boot-api,因为现在的模块和dubbo-service-provider-api是同parent,所以可以直接引入
dubbo-spring-boot-api org.lyn.bazinga1.0.0
3.1.4 我们现在dubbo-spring-boot-provider中给出HelloService接口的最简单实现
![f96ee1154ce0365838e47d6f354b34a3.png](https://i-blog.csdnimg.cn/blog_migrate/c8ffc9e81741c672ee1a921d5d251cc7.jpeg)
3.1.5 最后因为我们要请我们的主角登场,那就是dubbo,因为服务提供者端和服务消费者端都需要dubbo的jar包的依赖,所以dubbo的依赖我们放在dubbo-spring-boot-skeleton父工程中,这样子工程就不需要重复导入了,所在在父工程的pom.xml中引入如下maven依赖,注意不在dependencyManagement中,而是就是根依赖中
org.apache.dubbo dubbo-spring-boot-starter 2.7.0org.apache.dubbo dubbo 2.7.0org.apache.curator curator-framework 4.0.1org.apache.curator curator-recipes 4.0.1org.apache.zookeeper zookeeper 3.4.13
3.1.6 最后就轮到经典的SpringBoot的main函数启动类的书写了
![df3a9a654e34cdf8ef3634c71493a5f5.png](https://i-blog.csdnimg.cn/blog_migrate/285e1f70b5d4301de81344de5c71a58e.jpeg)
3.1.7 记住,别忘记还有我们的一些简单配置,例如我们tomcat的启动端口啊,dubbo的默认扫包路径啊,dubbo使用的协议等等,我们都需要再application.properties中配置
server.port=10086# Spring boot applicationspring.application.name=dubbo-spring-boot-provider# Base packages to scan Dubbo Component: @org.apache.dubbo.config.annotation.Servicedubbo.scan.base-packages=com.lyn.bazinga.service# Dubbo Application## The default value of dubbo.application.name is ${spring.application.name}## dubbo.application.name=${spring.application.name}# Dubbo Protocoldubbo.protocol.name=dubbodubbo.protocol.port=12345## Dubbo Registrydubbo.registry.address=zookeeper://localhost:2181
3.1.8 到此为止完整的服务提供者端就算完成了,看下基本骨架截图
![08fd3505ca28f4c9293d218ee89a0f6e.png](https://i-blog.csdnimg.cn/blog_migrate/e5e2f02956f8f07d9a0a70094b498e1d.jpeg)
3.2 启动SpringBootDubboProviderApplication的main函数发现并没有报错,并成功在10086端口监听
![f3bf3f29e946e573a486b83482595e2e.png](https://i-blog.csdnimg.cn/blog_migrate/93e2708d3dcf19023dbbb95174905718.jpeg)
到此为止服务提供者端的代码就完整结束了,接下来我们只要如法炮制,完成服务消费端的代码编写就可以收工了
4.1 dubbo-spring-boot-consumer端的pom.xml与dubbo-spring-boot-provider端是一模一样的,这边只要copy一下就ok了
4.1.1 首先我们写一个简单的Service,ConsumerService和其对应的实现类,这边的@Service是spring的注解,@Reference是dubbo的注解,这边需要注意
package org.lyn.bazinga.service.impl;import org.apache.dubbo.config.annotation.Reference;import org.lyn.bazinga.service.ConsumerService;import org.lyn.bazinga.service.api.HelloService;import org.springframework.stereotype.Service;@Servicepublic class ConsumerServiceImpl implements ConsumerService { @Reference(version = "1.0.0") private HelloService helloService; @Override public String hello(String name) { return helloService.hello(name); }}
4.1.2 然后我们通过一个Controller将其暴露出去
package org.lyn.bazinga.controller;import org.lyn.bazinga.service.ConsumerService;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestControllerpublic class HelloController { @Resource private ConsumerService consumerService; @GetMapping("/hello/{name}") public String hello(@PathVariable String name){ return consumerService.hello(name); }}
4.1.3 依旧是spring boot的main函数启动类和配置文件application.properties
package org.lyn.bazinga;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class SpringBootDubboConsumerApplication { public static void main(String[] args) { SpringApplication.run(SpringBootDubboConsumerApplication.class,args); }}
application.properties
server.port=10087# Spring boot applicationspring.application.name=dubbo-spring-boot-consumerserver.servlet.context-path=/dubbo-spring-boot-consumer## Dubbo Registrydubbo.registry.address=zookeeper://localhost:2181
4.1.4 完整的dubbo-spring-boot-consumer的代码结构如下
![8c044a44bdc6d061c3bdd546dfe8895d.png](https://i-blog.csdnimg.cn/blog_migrate/f6ff0b9313740fac15a1835437f5629e.jpeg)
三.测试整个链路
先启动服务提供者的main函数SpringBootDubboProviderApplication
![a9e49110e4f8a0ff8acb885c4a19a2a6.png](https://i-blog.csdnimg.cn/blog_migrate/3eb6da5868e96358e3cfc6ed3f9f8090.jpeg)
然后再启动SpringBootDubboConsumerApplication
![79e31004f5a78ff606fd4a06da8e1593.png](https://i-blog.csdnimg.cn/blog_migrate/13668bbd931072ced7149ad93df6552c.jpeg)
最后我们在浏览器中简单的访问一下URL:http://localhost:10087/dubbo-spring-boot-consumer/hello/lyncc
可以正常的返回结果:"spring boot & docker &lyncc " 说明我们整个链路全部打通了,大功告成
四 小结
1.首先先创建服务提供者,服务提供者在java开发中需要分模块创建,因为服务提供接口需要单独打成jar包,给服务消费者引用调用
2.服务提供者将服务的信息注册到zookeeper,监听本地的tcp12345的端口,等待客户端连接
3.服务消费者,发现自己需要调用com.bazinga.service.HelloService 版本是1.0.0的服务,服务消费者dubbo-spring-boot-consumer 把这个订阅信息发送给zookeeper,zookeeper返回这个服务的地址是ip:12345的地址,然后服务消费者使用Netty发送一个tcp请求,成功建立连接之后,服务提供者把结果返回
如果您看到这里,希望您点个关注,本文依旧原创,虽然很简单,也很入门,毕竟一步一个脚印吧,本文的代码也是比较多,希望PC端查看,如果是java的新手观众,建议一起手敲一下代码,先了解一下,java高手老爷们,有哪些做的不对的可以批评指正,接下来的一篇文章,应该是本地搭建新的Dubbo Admin,我们可爱的Dubbo服务治理控制台