简介
今天咱们来看看怎么利用 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 的路上越走越好.!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于