简介
今天咱们来看看怎么利用 Spring Boot 整合 Dubbox 来开发去中心化的微服务。
系统环境
本文基于 Jdk1.8/Maven 3.3.9/Spring Boot 1.4.2.RELEASE/Dubbo 2.8.5.SNAPSHOT(Dubbox 后续开源版本)/ZooKeeper3.4.8
Zookeeper 环境搭建
下载并安装启动
下载
wget http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.8/
解压
tar -zxf zookeeper-3.4.8.tar.gz
修改配置文件
cd zookeeper-3.4.8/conf cp zoo_sample.cfg zoo.cfg # zookeeper 默认是用../conf/zoo.cfg 如果没有这个文件则报错 vim zoo.cfg
好吧 我们不改了,我们使用默认的配置.哈!
启动
cd zookeeper-3.4.8/bin ./start.sh start #启动zookeeper 关闭: ./start.sh stop
Dubbox 环境准备
zookeeper 准备好了,先放着 一会再用.下面我们来准备下 Dubbox.
dubbox 是当当网基于 dubbo 开源的组件
为什么使用 dubbox?
因为 dubbox 支持更新的 spring 版本...
Dubbox 在 maven 中央仓库并没有对应的依赖,所以我们需要自己动手将其发布到我们的本地仓库来使用.
下载
我们这次从码云下载
git clone https://git.oschina.net/wuyu15255872976/dubbox.git
编译安装
cd dubbox mvn clean install -Dmaven.test.skip
等待 ... 等待...
之后我们在我们的 maven 本地仓库/com/alibaba/dubbo/2.8.5-SNAPSHOT 中会发现这么一个东西:
dubbo-2.8.5-SNAPSHOT.jar
这个玩意就是我们需要的 Dubbx 的 jar 包...
Spring Boot Dubbo 引导
dubbox 的 jar 包准备好了,行,咱先放着.一会再用.
下面来介绍下 spring-boot-starter-dubbo 项目的准备.
我们可能以前在使用 dubbo 的时候都是用的 xml 配置.在整合 Spring Boot 的时候呢是用的 @ImportResource
注解来引入的 dubbo 的 xml 配置.
但是 Spring Boot 本身并不推荐 xml 配置.怎么解决这个矛盾,我们可以自己准备一个 Spring Boot Starter dubbo 的项目来引导 Spring Boot 对 Dubbo 的自动化配置.
下载
git clone https://git.oschina.net/wuyu15255872976/spring-boot-starter-dubbo.git
感谢这位悲伤的大神的开源贡献!. 顶一个,赞两个.
修改 pom.xml
- 在环境准备的时候我们说过,我们的项目基于 Spring Boot 1.4.2.RELEASE ,但是我们 down 下来 spring-boot-starter-dubbo 的时候发现它用的是 1.3.6 的版本.我们动手自己改下 parent 的依赖吧.
- 我们发现在 pom.xml 中基本所有的依赖的
option
都是true
,我懒所以我想在其他项目依赖这个项目的时候不要再写一遍,所以我把<option>true</option>
都给干掉了...... 干不干掉这个倒是随意哈. - 刚上一个环节我们打包并安装到本地库的 Dubbox 在这个地方需要用上了. 我们修改
dubbo
的版本为2.8.5-SNAPSHOT
- 修改 java 版本为 1.8
完整 pom.xml 文件如下:
<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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.2.RELEASE</version> </parent> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.4.2.RELEASE</version> <name>Spring Boot Dubbo Rpc</name> <description>Spring Boot Dubbo Rpc</description> <url>http://projects.spring.io/spring-boot/</url> <organization> <name>Pivotal Software, Inc.</name> <url>http://www.spring.io</url> </organization> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.8.5-SNAPSHOT</version> <exclusions> <exclusion> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> </dependency> <!-- zookeeper 客户端 --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.4.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <artifactId>maven-source-plugin</artifactId> <configuration> <attach>true</attach> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
编译打包
上面我们对于 spring-boot-starter-dubbo 的准备工作完成,我们现在打包编译
mvn clean install -Dmaven.test.skip
然后我们去 maven 本地仓库中找到它:
xxx/org/springframework/boot/spring-boot-starter-dubbo/1.4.2.RELEASE/spring-boot-starter-dubbo-1.4.2.RELEASE.jar
dubbo 系统监控工具
这里我们使用韩都衣舍马老师提供的 dubbo-monitor
下载
git clone https://git.oschina.net/handu/dubbo-monitor.git
运行
根据项目 README.MD 我们先创建一个叫 monitor
的数据库,然后 maven 打包运行,我们也可以导入到 IDE 中直接运行,当然生产环境我们不能这么干.
我们的 home 页面:
一会儿我们需要在这里验证我们的 provider 和 consumer 是否已经成功.
基本工作已经准备妥当,我们来看下我们怎么使用它.
目录结构
首先我们来看一下整个 maven 项目的目录结构:
business --consumer ----pom.xml ----src/main/java --provier ----pom.xml ----src/main/java --service ----src/main/java --pom.xml
说明
-
business 作为父项目
-
consumer 是我们的服务消费者
-
provider 是我们的服务提供者
-
service 是提供 domain 和接口 service 的项目
为什么要单独把
service
建module
呢?因为我们写的
service(java interface)
和domain(java bean)
是需要在consumer和provider
端共享的.单独打成 jar 包有利用我们的
代码重用和序列化反序列化
.
基本结构介绍完成,下面我们分每一个模块来详细探讨.
business 父项目
既然 business 作为 maven 父项目,就做点它应该干的事.
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"> <modelVersion>4.0.0</modelVersion> <groupId>cn.veryjava</groupId> <artifactId>business</artifactId> <packaging>pom</packaging> <version>1.0</version> <name>business</name> <description>business</description> <organization> <name>veryjava</name> <url>http://blog.veryjava.cn</url> </organization> <developers> <developer> <name>sunshineasbefore</name> <email>work_wjj@163.com</email> </developer> </developers> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-boot.version>1.4.2.RELEASE</spring-boot.version> <spring-boot-dubbo.version>1.4.2.RELEASE</spring-boot-dubbo.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.2.RELEASE</version> <relativePath/> </parent> <modules> <module>service</module> <module>provider</module> <module>consumer</module> </modules> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-boot.version}</version> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>${spring-boot-dubbo.version}</version> <optional>true</optional> </dependency> </dependencies> </project>
在其中我们引入 spring-boot-starter-parent
spring-boot-starter-web
spring-boot-starter-test
spring-boot-starter-dubbo
,其中除了 spring-boot-starter-parent
我们定义其他依赖都可选.
没了...
service 子项目
service 子项目提供 domain 和 service 接口.
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>business</artifactId> <groupId>cn.veryjava</groupId> <version>1.0</version> </parent> <packaging>jar</packaging> <modelVersion>4.0.0</modelVersion> <artifactId>service</artifactId> </project>
定义一下 parent
和 artifactId
完事.
BusinessDomain.java
package cn.veryjava.business.domain; import java.io.Serializable; public class BusinessDomain implements Serializable{ private int id; private String name; public BusinessDomain(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
定义我们需要在 provider 和 consumer 中使用的 domain,实现 java.io.Serializable 来进行序列化.
dubbo 支持的序列化方式很多,这个可以参考 dubbo.io 里关于协议和序列化的介绍,我们使用默认的协议 dubbo
.
BusinessService.java
package cn.veryjava.business.service; import cn.veryjava.business.domain.BusinessDomain; public interface BusinessService { BusinessDomain findBusiness(int id, String name); }
定义我们需要在 provider 和 consumer 中使用的接口方法.
provider 子项目
我们的服务提供者.
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>business</artifactId> <groupId>cn.veryjava</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>provider</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>${spring-boot-dubbo.version}</version> </dependency> <dependency> <groupId>cn.veryjava</groupId> <artifactId>service</artifactId> <version>1.0</version> </dependency> </dependencies> </project>
定义 parent
和 artifactId
并引入 spring-boot-starter-web
spring-boot-starter-dubbo
service
依赖.
application.yml
server: port: 8081 spring: dubbo: application: name: business-provider registry: protocol: zookeeper address: localhost:2181,192.168.2.23:2181 protocol: name: dubbo port: 20880 host: localhost scan: cn.veryjava.business.provider
定义我们的 dubbo 配置.
服务注册发现使用 zookeeper
.协议使用 dubbo
,包扫描路径写 cn.veryjava.business.provider
ProviderApplication.java
package cn.veryjava.business.provider; import com.alibaba.boot.dubbo.EnableDubboAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableDubboAutoConfiguration public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
这是我们服务提供者的引导类.重点是 @EnableDubboAutoConfiguration
这个注解将引导我们自动化配置 dubbox
BusinessServiceImpl.java
package cn.veryjava.business.provider; import cn.veryjava.business.domain.BusinessDomain; import cn.veryjava.business.service.BusinessService; import com.alibaba.dubbo.config.annotation.Service; @Service(version = "1.0.0") public class BusinessServiceImpl implements BusinessService { @Override public BusinessDomain findBusiness(int id, String name) { return new BusinessDomain(id,name); } }
这个是我们需要提供的服务,重点是 @Service
这个注解,需要注意的是此 @Service
非彼 @Service
.
我们在这个地方使用的 @Service
是 dubbo 提供的,注意看 import 部分.然后,dubbo 的 springBoot 自动化配置会自动发现这个类并将其注册到 zookeeper.
当然我们使用 spring 提供的 @Service
也是可以的,不过这种方式比较麻烦.这个地方我们就不介绍了,有想了解的同学可以去 dubbo.io 去详细了解
编译运行
代码写好了,服务提供了,我们来验证下我们提供的服务是否能够成功注册并被发现.
启动后我们打开 dubbo-monitor
的 Services
页面,如果看到如下情况,则证明我们的服务已经注册成功:
注意观察其中 cn.veryjava.business.service.BusinessService
我们发现这个时候的 BusinessService
已经被提供但是还没有相应的消费者来使用.那么我们接下来看一下消费者怎么去使用.
consumer 子项目
这个是我们的服务消费者
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>business</artifactId> <groupId>cn.veryjava</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consumer</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>${spring-boot-dubbo.version}</version> </dependency> <dependency> <groupId>cn.veryjava</groupId> <artifactId>service</artifactId> <version>1.0</version> </dependency> </dependencies> </project>
定义 parent
artifactId
并引入 spring-boot-starter-web
spring-boot-starter-dubbo
service
依赖.
application.yml
server: port: 8777 spring: dubbo: application: name: business-consumer registry: protocol: zookeeper address: localhost:2181,192.168.2.23:2181 protocol: name: dubbo port: 20880 host: localhost scan: cn.veryjava.business.consumer.controller
实测 不写 scan
不行,可能是我刚开始理解有问题....我刚开始以为 scan
只是用来进行服务发现的,结果跟消费者进行消费也有关系...
ConsumerApplication.java
package cn.veryjava.business.consumer; import com.alibaba.boot.dubbo.EnableDubboAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableDubboAutoConfiguration public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
服务消费者引导类,@EnableDubboAutoConfiguration
注解也得写,原因同上.
BusinessConsumerController.java
package cn.veryjava.business.consumer.controller; import cn.veryjava.business.domain.BusinessDomain; import cn.veryjava.business.service.BusinessService; import com.alibaba.dubbo.config.annotation.Reference; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class BusinessConsumerController { @Reference(version = "1.0.0") public BusinessService businessService; @RequestMapping("/business") @ResponseBody public BusinessDomain getBusiness() { return businessService.findBusiness(1, "businessaaa"); } }
我们的 BusinessService
服务是怎么被消费的,怎么被依赖的.其实就是使用了 dubbo 提供的 @Reference
注解... 告诉 dubbo 我要使用哪个版本服务,就是这么简单....
编译运行
我们来测一下 dubbo-monitor
能否监控到服务的消费者吧.
启动后我们打开 dubbo-monitor
的 Services
页面,如果看到如下情况,则证明我们的服务已经注册成功并且消费者已经能够发现:
然后我们调用一下这个接口,看看到底是不是我们想要的数据.
curl -L http://localhost:8777/business
输出如下:
{"id":1,"name":"businessaaa"}
好吧,到这一步,我们的服务发现和服务消费都可以成功了.
总结
我们发现,dubbo 的使用还是很简单的,几乎没有任何的侵入性,也非常符合 Spring 的 IOC/DI
的理论概念.可以说跟 spring 的结合非常完美!
我们的这个小项目,仅仅只是用来学习的小项目,不过我们可以在此基础上对 zookeeper,对各个 provider/consumer 进行集群配置.这样我们就可以慢慢实现后台服务的去中心化,很大程度上提高了我们架构的可用性.
希望各位在 Java 的路上越走越好.!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于