本項目使用當前(2018年7月)最新的官方正式版本實踐,SpringBoot 2.0.3+dubbo-spring-boot-starter 0.2.0(即dubbo2.6.2)+zookeeper集羣
文章主要參考了Dubbo在Apache的項目主頁的文檔,還有Dubbo Spring Boot 工程在github的說明和例子
文章寫得較繁瑣,重點在後半部分
目錄:
一 項目結構
項目結構
項目名爲dubbo,其下分3個模塊base-interface,provider和consumer
- base-interface:基礎接口模塊,對應的即Dubbo服務
- provider:提供者
- consumer:消費者
模塊功能
- 相互關係
主項目dubbo負責版本管理,provider和consumer都依賴base-interface接口,其中,provider提供了接口的具體實現,而consumer則調用了provider的實現,他們通過base-interface來確定使用規範(接口即契約) - 對應MVC關係
對應到MVC的話,base-interface就是service(接口,爲提供實現),provider就相當於serviceImpl(service的實現類),而concumer就是controller的角色. - 框架依賴
所以base-interface是單純的服務接口集,不需要額外的依賴,而provider只提供服務實現,並不對外開放,只需對內提供服務調用就好,不需要spring-web支持,真正對外開放接口的就只有consumer
二 項目搭建
新建dubbo項目,在dubbo項目下添加base-interface,provider和consumer 3個模塊
修改各個模塊pom文件,組成項目結構,具體如下
1 在主項目dubbo的pom引入子模塊並進行依賴的版本管理
注意,這裏的packing是pom,子模塊爲jar
而且,子模塊不定義groupId和version,即跟隨主項目的groupId和version
另外,這裏的插件是maven-deploy-plugin,並沒有spring-boot-maven-plugin,因爲一些子模塊不需要(如base-interface)
<?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>com.linshen.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>dubbo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<!--引入的子模塊-->
<modules>
<module>base-interface</module>
<module>provider</module>
<module>consumer</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<dubbo-springboot.version>0.2.0</dubbo-springboot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-springboot.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-actuator</artifactId>
<version>${dubbo-springboot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
2 修改base-interface模塊如下
注意,這裏沒有引入spring-boot-maven-plugin插件,因爲base-interface並不是一個真正的SpringBoot項目,也沒有啓動類
<?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>
<artifactId>base-interface</artifactId>
<name>base-interface</name>
<parent>
<groupId>com.linshen.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
</project>
3 在模塊provider和consumer引入依賴
注意這裏引入了actuator,非必須,也可以去掉的
<?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>
<artifactId>provider</artifactId>
<packaging>jar</packaging>
<name>provider</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.linshen.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<!-- 基礎接口模塊-->
<dependency>
<groupId>com.linshen.dubbo</groupId>
<artifactId>base-interface</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
4 在consumer模塊中再引入web依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5 將base-interface的Application引導類刪除,其他無用的文件夾也刪去(如resource)
6 修改provider的Application引導類,使其按非web應用運行
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ProviderApplication.class)
.web(WebApplicationType.NONE)
.run(args);
}
}
至此,項目搭建完畢
三 功能實現
按照前文講的,我們來實現最基礎的問候功能(hello和goodbye)
1 在base-interface模塊定義接口
如下,是一個很單純的接口
public interface HelloService {
String sayHello(String name);
String sayGoodbye(String name);
}
2 在provider模塊實現接口
如下,重點在於@Service
註解
@Service(
version = "${hello.service.version}",
application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}",
registry = "${dubbo.registry.id}"
)
public class DefaultHelloService implements HelloService {
@Override
public String sayHello(String name) {
return "Hello "+name+" !";
}
@Override
public String sayGoodbye(String name) {
return "Goodbye "+name+" !";
}
application.yml文件如下:
注意,dubbo.registry.address請設置爲真實zookeeper地址,我這裏用的是zookeeper集羣,具體可參考上一篇文章:SpringBoot2+Dubbo 學習系列1:使用Docker部署zookeeper
如果要簡單的話可以像官方教程一樣直接用廣播,這樣就不需要使用註冊中心了(相應的,就不能指定dubbo.registry.protocol)
dubbo.registry.id = my-registry
dubbo.registry.address = N/A
另外注意這裏給了dubbo.protocol的參數,因爲provider是要通過dubbo協議來提供服務的(當然也可以用其他協議,這裏不展開)
spring:
application:
name: linshen-dubbo-provider1
server:
port: 9090
dubbo:
registry:
protocol: zookeeper
address: ip:2181,ip:2182,ip:2183
id: lin-registry-1
protocol:
port: 12345
name: dubbo
id: dubbo
status: server
application:
name: linshen-dubbo-provider-name1
id: linshen-dubbo-provider-id1
qos-enable: true
qos-port: 22222
scan:
basePackages: com.linshen.dubbo.provider.service
hello:
service:
version: 1.0.0
3 在consumer模塊編寫controller
如下,重點在於@Reference
注意,下面的註解中在官方給的例子中是把registry換成url,如url = “dubbo://localhost:12345”來指定dubbo服務地址,這樣下面yml文件就可以不用寫dubbo.registry板塊了(畢竟官方給的例子沒有真正的註冊中心),但我還是覺得使用一開始就使用zookeeper會更加自然,更容易理解
@RestController
public class HelloController {
@Reference(
version = "${hello.service.version}",
application = "${dubbo.application.id}",
registry = "${dubbo.registry.id}"
)
private HelloService helloService;
@GetMapping("hello/{name}")
public String sayHello(@PathVariable String name){
return helloService.sayHello(name);
}
@GetMapping("goodbye/{name}")
public String sayGoodbye(@PathVariable String name){
return helloService.sayGoodbye(name);
}
}
application.yml文件如下:
注意,這裏我開啓了actuator
spring:
application:
name: linshen-dubbo-consumer1
server:
port: 9091
hello:
service:
version: 1.0.0
dubbo:
application:
id: linshen-dubbo-consumer-id1
name: linshen-dubbo-consumer-name1
registry:
protocol: zookeeper
address: ip:2181,ip:2182,ip:2183
id: lin-registry-1
management:
endpoint:
dubbo-configs:
enabled: true
dubbo:
enabled: true
dubbo-services:
enabled: true
dubbo-properties:
enabled: true
dubbo-shutdown:
enabled: true
dubbo-references:
enabled: true
health:
dubbo:
status:
defaults: memory
extras: load,threadpool
endpoints:
web:
exposure:
include: '*'
至此項目搭建結束
四 項目啓動並測試
1 啓動項目
啓動provider,觀察日誌
如圖是隻是日誌的一部分,其中紅線爲本機ip,藍線爲zookeeper所在主機ip,綠框爲連接建立狀態,從日誌中也可以看出來,大概流程是先初始化客戶端連接到zookeeper集羣,在開通一個socket連接到一臺zookeeper主機,,接着就註冊當前客戶端信息(包含dubbo協議地址,服務信息等等,如截圖),然後與註冊中心建立連接完成,會話建立,狀態更改爲CONNECTED,然後註冊中心會訂閱此provider信息並通知所有訂閱此provider信息的url.(這個流程只是從日誌上粗略地看的,並不一定準確)
啓動consumer,觀察日誌
前面和provider差不多,也是要把自身註冊到zookeeper上的,註冊完後還會多一些步驟,如下圖
可以很直觀地看到,註冊完之後紅線比藍線要多得多,因爲註冊完之後就和zookeeper沒什麼事了,consumer從註冊中心獲得provider的信息後,便直接和provider建立連接,如圖中所示,是通過NettyClient建立的連接,然後從註冊中心查閱特定的dubbo service服務,然後建立引用關係
2 測試
使用PostMan測試如下(其實直接用鏈接打開就可以測試了…)
使用actuator查看如下
以簡單地查看dubbo信息爲例:
dubbo還開放了很多其他的endpoint來監控
如dubbo/configs查看配置信息,dubbo/references查看引用實體等.
需要注意的是,由於使用的是SpringBoot2,所以Actuator的基礎路徑是ip:port/actuator,以前只是ip:port而已,這一點在dubbo的官方說明裏還沒有更改,詳情請看Spring Boot 2.0官方文檔之 Actuator
其他
到目前來看監控還是很不方便的,特別是當服務較多的時候,我們都值得Spring Cloud的服務治理中心是有終端網頁的,圖形化界面,關係看起來非常直觀,舒服,當然Dubbo也有,而且還原生支持中文,那就是Dubbo Admin,只不過它得另外部署,界面如下,部署放在下一篇文章說:Spring Boot 2+Dubbo 學習系列3:dubbo-ops 之 Dubbo Admin
文章參考:
http://dubbo.apache.org
http://start.dubbo.io/
https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/README_CN.md
Spring Boot 2+Dubbo 學習系列1:使用Docker部署zookeeper
Spring Boot 2+Dubbo 學習系列2:搭建Spring Boot 2+Dubbo+Zookeeper集羣
Spring Boot 2+Dubbo 學習系列3:dubbo-ops 之 Dubbo Admin