Doubbo
1. 学习目标
2. RPC架构
2.1 什么是RPC?
是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
**本质上就是:**远程过程调用
**特点:**应用直接调用服务,服务之间是隔离的。
**缺点:**服务过多时,管理成本昂贵。服务治理,服务注册,发现,服务容错,服务跟踪,服务网关,IP暴露等都是此架构无法避免的问题。
3.RPC基于RMI的简单实现。
3.1 RPC协议
RPC是一种远程过程调用的协议,使用这种协议向另一台计算机上的程序请求服务,不需要了解底层网络技术的协议。
在 RPC 中,发出请求的程序是客户程序,而提供服务的程序是服务器。
3.2 RPC-RMI项目搭建实例
1.首先创建一个空maven工程的父项目
2.不要选父工程
3.删除项目中的src文件和pom.xml中的一些依赖
- 添加父工程RPCRMI的pom依赖
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pan</groupId>
<artifactId>RPCRMI</artifactId>
<packaging>pom</packaging>
<name>RPCRMI</name>
<version>1.0-SNAPSHOT</version>
<!--创建子项目后会自动引入子项目的依赖-->
<modules>
<module>api</module>
<module>provider</module>
<module>consumer</module>
</modules>
<properties>
<java.version>1.8</java.version>
<dubbo.version>3.0.0</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<!--dubbo依赖-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
- 添加第一个子项目api
6.添加子工程api的pom依赖
<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>
<artifactId>RPCRMI</artifactId>
<groupId>com.pan</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--自己-->
<groupId>com.pan</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
7.创建类和接口
package com.pan.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String username;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
public User() {}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
}
package com.pan.service;
import com.pan.pojo.User;
/**
* 提供服务
*/
public interface IUserService {
User queryUserById(Integer id) throws Exception;
}
8.创建服务提供者
9.向provider中的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引入父工程关联起来-->
<parent>
<artifactId>RPCRMI</artifactId>
<groupId>com.pan</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--provider自己-->
<groupId>com.pan</groupId>
<artifactId>provider</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--api依赖 使它们关联起来-->
<dependency>
<groupId>com.pan</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
10.创建一个配置文件
package com.pan.config;
import com.pan.api.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.rmi.RmiServiceExporter;
@Configuration
public class RMIServer {
@Autowired
private IUserService userService;
@Bean
public RmiServiceExporter getRmiServiceExporter(){
RmiServiceExporter rmiServiceExporter = new RmiServiceExporter();
rmiServiceExporter.setServiceName("userService");
rmiServiceExporter.setService(userService);
rmiServiceExporter.setServiceInterface(IUserService.class);
rmiServiceExporter.setRegistryPort(2002);
return rmiServiceExporter;
}
}
11.创建用户提供方
package com.pan.server;
import com.pan.api.pojo.User;
import com.pan.api.service.IUserService;
import org.springframework.stereotype.Service;
/**
* 用户的提供方
*/
@Service
public class UserServiceImpl implements IUserService {
@Override
public User queryUserById(Integer id) throws Exception {
User user = new User();
user.setId(id);
user.setUsername("张三");
System.out.println("提供服务,接收到客户端的用户id为"+id);
return user;
}
}
12.启动类
package com.pan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 服务方
*/
@SpringBootApplication
public class RMIServiceApplication {
public static void main(String[] args) {
SpringApplication.run(RMIServiceApplication.class,args);
}
}
13.yml文件
#防止端口被占用
server:
port: 8001
14.创建客户端服务消费者consumer
consumer的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引入父工程依赖-->
<parent>
<artifactId>dubbo-rmi</artifactId>
<groupId>com.pan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!--consumer自己-->
<groupId>com.pan</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--引入api依赖-->
<dependency>
<groupId>com.pan</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
package com.pan.client;
import com.xxxx.api.service.IUserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
@Configuration
public class RMIClient {
@Bean
public RmiProxyFactoryBean getRmiProxyFactoryBean() {
RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
rmiProxyFactoryBean.setServiceUrl("rmi://127.0.0.1:2002/userService");
rmiProxyFactoryBean.setServiceInterface(IUserService.class);
return rmiProxyFactoryBean;
}
}
package com.pan.client;
import com.pan.api.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class UserInit implements CommandLineRunner {
@Autowired
private IUserService userService;
@Override
public void run(String... args) throws Exception {
System.out.println(userService.queryUserById(2));
}
}
启动类
package com.pan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 消费方
*/
@SpringBootApplication
public class RMIClientApplication {
public static void main(String[] args) {
SpringApplication.run(RMIClientApplication.class,args);
}
}
consumer的yml文件
#防止端口被占用
server:
port: 8002
4.SpringBoot整合dubbo
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提
供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅
自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调
用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基
于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发
送一次统计数据到监控中心
父工程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>
<modules>
<module>api</module>
<module>provider</module>
<module>consumer</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.pan</groupId>
<artifactId>dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>dubbo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<dubbo.version>3.0.0</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<!--dubbo依赖-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
api模块的pom依赖
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<!--父工程-->
<parent>
<groupId>com.pan</groupId>
<artifactId>dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/>
</parent>
<!--自己-->
<groupId>com.pan</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--web组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--dubbo依赖-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
package com.pan.api.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String username;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
public User() {}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
}
package com.pan.api.service;
import com.pan.api.pojo.User;
/**
* 提供服务
*/
public interface IUserService {
User queryUserById(Integer id) throws Exception;
}
provider的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引入父工程,关联起来-->
<parent>
<artifactId>dubbo</artifactId>
<groupId>com.pan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!--自己-->
<groupId>com.pan</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--引入api依赖 使它们关联起来-->
<dependency>
<groupId>com.pan</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--引入dubbo-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
</project>
package com.pan.provider.serviceImpl;
import com.alibaba.dubbo.config.annotation.Service;
import com.pan.api.pojo.User;
import com.pan.api.service.IUserService;
import org.springframework.stereotype.Component;
/**
* 用户的提供方
*/
@Component
@Service(interfaceClass = IUserService.class)//import com.alibaba.dubbo.config.annotation.Service;
public class UserServiceImpl implements IUserService {
@Override
public User queryUserById(Integer id) throws Exception {
User user = new User();
user.setId(id);
user.setUsername("张三");
System.out.println("提供服务,接收到客户端的用户id为"+id);
return user;
}
}
package com.pan.provider;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
/**
* 服务方
*/
@SpringBootApplication
@EnableCaching//开启缓存
@EnableDubbo//开启dubbo
public class DubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplication.class,args);
}
}
server:
port: 8001 #防止端口被占用
spring:
application:
name: dubbo #应用名称
dubbo:
server: true #开启dubbo
application:
name: provider #应用信息
registry:
address: zookeeper://127.0.0.1:2181 #注册中心地址
protocol:
name: dubbo #协议名
port: 20880 #协议端口
scan: com.pan.provider.service #扫描包的位置
consumer的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引入父工程依赖-->
<parent>
<artifactId>dubbo</artifactId>
<groupId>com.pan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!--自己-->
<groupId>com.pan</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--引入api依赖-->
<dependency>
<groupId>com.pan</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
package com.pan.consumer;
import com.alibaba.dubbo.config.annotation.Reference;
import com.pan.api.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class UserInit implements CommandLineRunner {
//dubbo项目注入属性不能用@Autowired 需要import com.alibaba.dubbo.config.annotation.Reference;
@Reference(interfaceClass = IUserService.class)
private IUserService userService;
@Override
public void run(String... args) throws Exception {
System.out.println(userService.queryUserById(2));
}
}
package com.pan;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 消费方
*/
@SpringBootApplication
@EnableDubbo//开启dubbo
public class DubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboConsumerApplication.class,args);
}
}
#防止端口被占用
server:
port: 8002
spring:
application:
name: dubbo #应用名称
dubbo:
application:
name: consumer #应用信息
registry:
address: zookeeper://127.0.0.1:2181 #注册中心地址 #multicast://224.5.6.7:1234 #注册中心地址
protocol:
name: dubbo #协议名
port: 20880 #协议端口
scan: com.pan.consumer #扫描包的位置