前言
上一次使用Dubbo還是用的Dubbo
2.7.3版本的,最近有個項目打算用Dubbo來開發(fā),查閱了文檔,發(fā)現(xiàn)其最新的版本是3.x版本了,但是相關文檔貌似還沒有整理好,官方顯示是在建設中,所以我使用了所謂穩(wěn)定點的版本2.7.7,發(fā)現(xiàn)2.7.7版本已經有了些許的改動了,所以自己踩了一遍坑,做了這個Demo來記錄下。
問題紀要
由于版本變更以及之前沒有使用過Nacos作為Dubbo的注冊中心,以至于集成的過程中遇到了一些問題,所以這里先給說明下遇到的問題
注解變更
由于@service和Spring中的@repository和@service太容易混淆啦,許多人在issues上提出了該問題,在2.7.7版本的時候調整為了@DubboService 和 @DubboReference
無需@EnableDubbo
無需再啟動類上添加@EnableDubbo注解了,在我測試的過程中,發(fā)現(xiàn)了只要在代碼中使用了@DubboService或@DubboReference就會自動啟用Dubbo。
使用Nacos做注冊中心的時候,我發(fā)現(xiàn)沒有引入相關
DubboService的時候,我的消費服務雖然配置好了duboo相關的參數(shù),都是nacos服務列表沒有顯示出來,當我使用了DubboService的時候,服務列表就出現(xiàn)了
Nacos 1.4.0服務列表不顯示
不知道是否某些地方配置的問題,我使用Nacos 1.4.0的時候服務列表總是顯示不出來(即使我的nacos-client也同步使用1.4.0),換成1.3.2或1.3.1就可以顯示出來了,但是調用是正常的,/(ㄒoㄒ)/~~。
Demo解讀
目錄解讀
├─common-api # 公共APi的包
├─consume-service-nacos # Nacos作為注冊中心的消費者模塊
├─consumer-service-zookeeper # zookeeper作為注冊中心的消費者模塊
├─provider-service-nacos # Nacos作為注冊中心的服務提供者模塊
└─provider-service-zookeeper # zookeeper作為注冊中心的服務提供者模塊
關于不同注冊中心
Dobbo如果需要使用不同的注冊中心的話不需要修改業(yè)務邏輯代碼,只需要修改POM文件和配置文件即可,所以本文將先說明下公共的業(yè)務代碼,然后再分別提供Nacos和Zookeeper的pom和配置文件。
common-api
這里就定義了一個Model和一個接口,這里需要注意的是如果返回值是Model的話需要是可序列化的一個對象。
│common-api
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─martain
│ │ │ └─common
│ │ │ └─api
│ │ │ │ IUserService.java # 接口
│ │ │ └─vo
│ │ │ User.java # model
public class User implements Serializable {
private String id;
private String userName;
private Integer age;
...getter and setter ...
}
public interface IUserService {
/**
* 通過Id獲取用戶
* @param userId 用戶ID
* @return 用戶實體
*/
User getUserById(String userId);
}
服務提供者
│ ├─java
│ │ └─com
│ │ └─martain
│ │ └─provide
│ │ │ ProviderServiceXXX.java # 啟動類
│ │ └─service
│ │ UserService.java # 服務實現(xiàn)類
│ │
│ └─resources
│ application.yml # 配置文件
│ pom.xml # pom 文件
POM文件
Nacos
<properties>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
<dubbo.version>2.7.7</dubbo.version>
<nacos.version>1.3.2</nacos.version>
</properties>
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- api -->
<dependency>
<groupId>com.martain</groupId>
<artifactId>common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!-- Dubbo Registry Nacos -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
</dependencies>
Zookeeper
<properties>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
<dubbo.version>2.7.7</dubbo.version>
</properties>
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!-- 公共api -->
<dependency>
<groupId>com.martain</groupId>
<artifactId>common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Zookeeper dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
配置文件
spring:
application:
name: provider-service
dubbo:
application:
name: provider-service
registry:
address: zookeeper://127.0.0.1:2181 # 如果是nacos 就填 nacos://127.0.0.1:8848
timeout: 10000
protocol:
name: dubbo
port: 20880
scan:
base-packages: com.martain.provide.service
metadata-report:
address: zookeeper://127.0.0.1:2181 # 如果是nacos 就填 nacos://127.0.0.1:8848
userService
接口實現(xiàn)類上需要添加
@DubboService注解,表名這個類中的接口是需要注冊到注冊中心去的。而這個注解也有許多可選參數(shù),詳情可查看dubbo的源碼了解這些參數(shù)的作用。dubbo官方推薦做法是盡量在provider端多做配置,比如timeout這種配置,應該在服務提供者端配置,而不是在消費者端配置,因為提供者更清楚他提供的方法大致會花費多長時間。(雖然按照dubbo的配置覆蓋規(guī)則,在consumer端的配置會覆蓋provider端的配置)。
<details>
<summary>@DubboService</summary>
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Inherited
public @interface DubboService {
Class<?> interfaceClass() default void.class;
String interfaceName() default "";
String version() default "";
String group() default "";
String path() default "";
boolean export() default true;
String token() default "";
boolean deprecated() default false;
boolean dynamic() default true;
String accesslog() default "";
int executes() default 0;
boolean register() default true;
int weight() default 0;
String document() default "";
int delay() default 0;
/** @deprecated */
String local() default "";
String stub() default "";
String cluster() default "";
String proxy() default "";
int connections() default 0;
int callbacks() default 1;
String onconnect() default "";
String ondisconnect() default "";
String owner() default "";
String layer() default "";
int retries() default 2;
String loadbalance() default "random";
boolean async() default false;
int actives() default 0;
boolean sent() default false;
String mock() default "";
String validation() default "";
int timeout() default 0;
String cache() default "";
String[] filter() default {};
String[] listener() default {};
String[] parameters() default {};
String application() default "";
String module() default "";
String provider() default "";
String[] protocol() default {};
String monitor() default "";
String[] registry() default {};
String tag() default "";
Method[] methods() default {};
}
</details>
package com.martain.provide.service;
import com.martain.common.api.IUserService;
import com.martain.common.api.vo.User;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService
public class UserService implements IUserService {
public User getUserById(String userId) {
User user = new User();
user.setId(userId);
user.setUserName("小明");
user.setAge(18);
return user;
}
}
Application 啟動類
啟動類上添加
@EnableAutoConfiguration注解即可,這個注解也是spring的自動配置的注解。
package com.martain.provide;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
@EnableAutoConfiguration
public class ProviderServiceZookeeper {
public static void main(String[] args) {
new SpringApplicationBuilder(ProviderServiceZookeeper.class).run(args);
}
}
服務消費者
服務消費者
│ pom.xml # POM文件
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─martain
│ │ │ └─consumer
│ │ │ │ ConsumerServiceZookeeper.java # 啟動類
│ │ │ └─controller
│ │ │ UserController.java # web控制器
│ │ │
│ │ └─resources
│ │ application.yml # 配置文件
POM文件
Nacos
<properties>
<spring-boot.version>2.3.3.RELEASE</spring-boot.version>
<dubbo.version>2.7.7</dubbo.version>
<nacos.version>1.3.2</nacos.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.martain</groupId>
<artifactId>common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!-- Dubbo Registry Nacos -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
</dependencies>
Zookeeper
<properties>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
<dubbo.version>2.7.7</dubbo.version>
</properties>
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.martain</groupId>
<artifactId>common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Zookeeper dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
配置文件
dubbo:
application:
name: consumer-service
registry:
address: nacos://127.0.0.1:8848 # 如果是zookeeper 就填 zookeeper://127.0.0.1:2181
UserController
需要在接口上添加
@DubboReference注解聲名該接口的服務器要是dubbo服務,需要去遠程調用。
<details>
<summary>@DubboReference</summary>
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface DubboReference {
Class<?> interfaceClass() default void.class;
String interfaceName() default "";
String version() default "";
String group() default "";
String url() default "";
String client() default "";
boolean generic() default false;
boolean injvm() default true;
boolean check() default true;
boolean init() default false;
boolean lazy() default false;
boolean stubevent() default false;
String reconnect() default "";
boolean sticky() default false;
String proxy() default "";
String stub() default "";
String cluster() default "";
int connections() default 0;
int callbacks() default 0;
String onconnect() default "";
String ondisconnect() default "";
String owner() default "";
String layer() default "";
int retries() default 2;
String loadbalance() default "";
boolean async() default false;
int actives() default 0;
boolean sent() default false;
String mock() default "";
String validation() default "";
int timeout() default 0;
String cache() default "";
String[] filter() default {};
String[] listener() default {};
String[] parameters() default {};
String application() default "";
String module() default "";
String consumer() default "";
String monitor() default "";
String[] registry() default {};
String protocol() default "";
String tag() default "";
String merger() default "";
Method[] methods() default {};
String id() default "";
}
</details>
package com.martain.consumer.controller;
import com.martain.common.api.IUserService;
import com.martain.common.api.vo.User;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@DubboReference
IUserService userService;
@GetMapping("/getUserInfo/{userId}")
public Object getUserInfo(@PathVariable String userId){
return userService.getUserById(userId);
}
}
Application 啟動類
和普通的springboot項目一致即可
package com.martain.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerServiceZookeeper {
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceZookeeper.class,args)
}
}
測試
訪問 http://127.0.0.1:8080/user/getUserInfo/123
附件
