Quick Start
Dubbo!用更优雅的方式来实现RPC调用吧 - 掘金
dubbo+zookeeper demo
项目结构:
RpcService
仅仅是提供服务的接口:
public interface HelloService {
String sayHello(String name);
}
DubboServer
pom:
<?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 https://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>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>DubboServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>DubboServer</name>
<description>DubboServer</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<version>0.2.0</version>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.5</version>
</dependency>
<!-- Spring Context Extras -->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>RpcService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<!-- 这是个编译java代码的 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
DubboServerApplication:
package com.example.dubboserver;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo(scanBasePackages = {"com.example.dubboserver"})
public class DubboServerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboServerApplication.class, args);
}
}
HelloServiceImpl实现dubbo服务:
package com.example.dubboserver;
import com.alibaba.dubbo.config.annotation.Service;
import com.example.rpcservice.HelloService;
import org.springframework.stereotype.Component;
@Component
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "hello " + name + "!";
}
}
配置文件application.yaml:
dubbo:
application:
name: example-provider
registry:
address: zookeeper://43.143.229.22:2181
protocol:
name: dubbo
port: 20880
zookeeper是我的一台云服务器,zookeeper需要先部署好。
DubboClient
pom文件与Server相似:
<?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 https://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>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>DubboClient</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>DubboClient</name>
<description>DubboClient</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>RpcService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<version>0.2.0</version>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.5</version>
</dependency>
<!-- Spring Context Extras -->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
DubboClientApplication:
package com.example.dubboclient;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo(scanBasePackages = {"com.example.dubboclient"})
public class DubboClientApplication {
public static void main(String[] args) {
SpringApplication.run(DubboClientApplication.class, args);
}
}
RpcService:
package com.example.dubboclient;
import com.alibaba.dubbo.config.annotation.Reference;
import com.example.rpcservice.HelloService;
import org.springframework.stereotype.Service;
@Service
public class RpcService {
@Reference
private HelloService helloService;
public String getHelloServiceResponse(String name) {
return helloService.sayHello(name);
}
}
通过Reference注解标识这是一个dubbo服务接口。
TriggerController:(通过get方法触发dubbo调用,debug用)
package com.example.dubboclient;
import org.springframework.beans.factory.annotation.Autowired;
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("/demo/dubbo")
public class TriggerController {
@Autowired
private RpcService rpcService;
@GetMapping("/{name}")
public String getTime(@PathVariable("name") String name) {
return rpcService.getHelloServiceResponse(name);
}
}
配置文件:
server:
port: 8081
dubbo:
application:
name: example-consumer
registry:
address: zookeeper://43.143.229.22:2181
client: curator
protocol:
name: dubbo
server: false
consumer:
timeout: 3000
dubbo使用nacos作为注册中心
dubbo也可以用nacos作为注册中心。使用docker一键启动nacos2: docker run --name nacos-quick -e MODE=standalone -p 8848:8848 -p 9848:9848 -p 9849:9849 -d nacos/nacos-server:2.0.2
,如果是部署在云服务器上的话记得防火墙暴露接口。
client和server的代码与上面zookeeper的一致,但是依赖和配置换了,依赖采用alibaba-spring-cloud来提供。这里我为了方便没有创建父项目写dependencyManagement,而是直接在子项目写来管理包版本,这种做法不是很规范。
Server
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 https://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>2.6.3</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>DubboServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>DubboServer</name>
<description>DubboServer</description>
<properties>
<spring-cloud-clibaba.version>2021.0.1.0</spring-cloud-clibaba.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring cloud 版本控制 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 版本控制 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-clibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- nacos 配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>RpcService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<!-- 这是个编译java代码的 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
application.yaml:
spring:
main:
# spring boot 2.6.3默认不允许循环依赖, dubbo的这个版本存在循环依赖
allow-circular-references: true
application:
name: demo-server
cloud:
nacos:
config:
enable: false
discovery:
server-addr: 123.56.98.228:8848
namespace: public
dubbo:
consumer:
retries: 5
protocol:
port: -1
name: dubbo
scan:
# 扫描实现类的包路径(可配置多个或数组)
base-packages: com.example.dubboserver # 更改为自己dubbo实现类的路径
registry:
address: nacos://${spring.cloud.nacos.discovery.server-addr}?namespace=${spring.cloud.nacos.discovery.namespace}
cloud:
# 默认*订阅所有, 所以在此处写一个不存在的提供者
# (可订阅多个用,隔开或者用数组的配置方式 -: name)
subscribed-services: "-"
client
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 https://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>2.6.3</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>DubboClient</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>DubboClient</name>
<description>DubboClient</description>
<properties>
<spring-cloud-clibaba.version>2021.0.1.0</spring-cloud-clibaba.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring cloud 版本控制 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 版本控制 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-clibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>RpcService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- nacos 配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yaml:
spring:
main:
# spring boot 2.6.3默认不允许循环依赖, dubbo的这个版本存在循环依赖
allow-circular-references: true
application:
name: demo-client
cloud:
nacos:
config:
enable: false
discovery:
server-addr: 123.56.98.228:8848
namespace: public
dubbo:
consumer:
retries: 5
protocol:
port: -1
name: dubbo # 协议名称
测试
先上nacos看看服务 ip:8848/nacos:
其中有一个是dubbo自己的服务,剩下三个一个是client应用,一个是server应用,一个是暴露的RpcService服务。
浏览器输入:http://localhost:8080/demo/dubbo/dsasdfaasdf
响应:
没啥问题。
dubbo泛化调用
dubbo泛化调用即在调用方不引入服务方接口包的情况下直接调用服务接口。
适用场景:
比如你做了一个网关项目,网关需要调用后端的多个服务的多个接口,这些接口假如都是dubbo,网关需要引入所有服务的接口包才能调用,这显然不太合理,网关的代码应该和后端服务解耦。
那如何实现泛化调用呢?
- 服务方不需要更改配置。
- 调用方更改rpc调用的代码。
不使用泛化调用的代码:
@Service
public class RpcService {
@Reference
private HelloService helloService; // 普通调用
public String getHelloServiceResponse(String name) {
return helloService.sayHello(name); // 普通调用
}
}
改为泛化调用:
@Service
public class RpcService {
@DubboReference(interfaceName = "com.example.rpcservice.HelloService", generic = true)
private GenericService genericService;
public String getHelloServiceResponse(String name) {
Object res = genericService.$invoke("sayHello" , new String[]{"java.lang.String"},
new Object[]{name});
return (String) res;
}
}
可以看到将原本的具体的Service接口改为了GenericService, @DubboReference中写明了调用的接口全限定名称,并且generic打开为true。
至此完成泛化调用改动,还是挺简单的。