概念
RPC(Remote Procedure Call Protocol):远程过程调用:
两台服务器A、B,分别部署不同的应用a,b。当A服务器想要调用B服务器上应用b提供的函数或方法的时候,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义传达调用的数据。
说白了,就是你在你的机器上写了一个程序,我这边是无法直接调用的,这个时候就出现了一个远程服务调用的概念。
目录结构
依赖管理
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>
<artifactId>dubbo-stuty01-start</artifactId>
<groupId>yh</groupId>
<version>1.0-SNAPSHOT</version>
<properties>
<!--指定jdk版本-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--add maven release 防止idea每次都默认以1.5版本编译的maven设置(Target bytecode version)-->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<encoding>UTF-8</encoding>
<!--依赖版本设置-->
<spring.version>4.3.7.RELEASE</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring 基本依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!--dubbo依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
</dependency>
<!-- zookeeper注册中心客户端依赖-->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
</project>
服务接口
在新建包com.yh.dubbo下创建服务接口,该接口是服务提供者和消费者同时能看到的。
package com.yh.dubbo;
/**
* @Description: service 接口,提供者和消费者都能看到。实现由提供者来完成。
* @Author: 张颖辉(yh)
* @Date: 2018/7/24 17:08
* @param:
* @return:
* @Version: 1.0
*/
public interface IDemoService {
public String sayHello(String name);
}
服务实现
新建提供者包:com.yh.dubbo.provider 下创建服务实现类
package com.yh.dubbo.provider;
import com.yh.dubbo.IDemoService;
/**
* @Description: Description
* @Author: 张颖辉(yh)
* @CreateDate: 2018/7/17 10:21
* @UpdateUser: 张颖辉(yh)
* @UpdateDate: 2018/7/17 10:21
* @UpdateRemark: The modified content
* @Version: 1.0
*/
public class DemoServiceImpl implements IDemoService {
@Override
public String sayHello(String name) {
return "Hello,"+name;
}
}
提供者配置
基于spring的服务提供者配置spring-provider.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="start-provider"/>
<!-- 使用multicast广播注册中心暴露服务地址 -->
<!--<dubbo:registry address="multicast://224.5.6.7:1234"/>-->
<!-- 使用 zookeeper 作为注册中心 注册服务-->
<dubbo:registry address="zookeeper://192.168.5.100:2181"/>
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.yh.dubbo.IDemoService" ref="demoService"/>
<!-- 和本地bean一样实现服务 -->
<bean id="demoService" class="com.yh.dubbo.provider.DemoServiceImpl"/>
</beans>
从配置中可以看出注册中心使用的zookeeper这也是官方推荐使用的注册中心,如果为了快速入门,没有安装zookeeper,那么可以换为多播/组播来替代zk作为注册中心,最后会讲怎么来使用多播/组播来做注册中心。
提供者启动类
服务提供者加载spring-provider.xml配置文件的启动入口
package com.yh.dubbo.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* @Description: Description
* @Author: 张颖辉(yh)
* @CreateDate: 2018/7/17 10:37
* @UpdateUser: 张颖辉(yh)
* @UpdateDate: 2018/7/17 10:37
* @UpdateRemark: The modified content
* @Version: 1.0
*/
public class ProviderStart {
public static void main(String[] args) throws IOException {
// ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
// new String[]{"http://10.20.160.198/wiki/display/dubbo/provider.xml"});
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"spring-provider.xml"});
context.start();
System.in.read();
}
}
消费者配置
服务消费者配置spring-consumer.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="start-consumer"/>
<!-- 使用multicast广播注册中心暴露发现服务地址 -->
<!--<dubbo:registry address="multicast://224.5.6.7:1234"/>-->
<!-- 使用 zookeeper 作为注册中心 发现服务-->
<dubbo:registry address="zookeeper://192.168.5.100:2181"/>
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="demoService" interface="com.yh.dubbo.IDemoService"/>
</beans>
在上面的配置中我们看到,和服务相关的只引用了服务的接口,并没有使用服务的实现类。最后我们要通过dubbo来展现出RPC的效果。
消费者启动类
服务消费者加载配置文件spring-consumer.xml,启动spring容器后并调用服务
package com.yh.dubbo.consumer;
import com.yh.dubbo.IDemoService;
import com.yh.dubbo.provider.DemoServiceImpl;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Scanner;
/**
* @Description: 消费者启动,并调用服务
* @Author: 张颖辉(yh)
* @CreateDate: 2018/7/17 10:37
* @UpdateUser: 张颖辉(yh)
* @UpdateDate: 2018/7/17 10:37
* @UpdateRemark: The modified content
* @Version: 1.0
*/
public class ConsumerStart {
public static void main(String[] args) {
// ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
// new String[]{"http://10.20.160.198/wiki/display/dubbo/consumer.xml"});
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"spring-consumer.xml"});
context.start();
IDemoService demoService=(IDemoService)context.getBean("demoService");
System.out.println(demoService.sayHello("yh"));
while (true){
Scanner scanner=new Scanner(System.in);
System.out.println(demoService.sayHello(scanner.next()));
}
}
}
运行效果
分别启动服务提供者和消费者,就是上面的代码中的两个main函数。
会在消费者的控制台看到:
这说明消费者端可以正确的调用提供者对service接口的实现,并返回了期望的结果。
之后再控制台手动输入文字,回车
手动输入的内容也正确的被处理和返回。
到此我们简单的实现了dubbo的使用了,上面的启动我们是靠着两个main函数启动的,实际上我们只要按照上面配置。在项目的spring容器启动的时候dubbo也会随之启动,并且消费者这边会自动将服务的实现类对象装载到spring容器中,和平常一样使用去注入service即可。
使用 multicast(多播/注册)作为注册中心
将上文中的两个spring配置文件的<dubbo:registry>配置中多播的部分解除注释,把zookeeper部分的注释掉。
注意:zookeeper需要使用你自己安装的IP地址和端口号,但是多播/组播中配置的IP端口不需要任何改动。
重复上面的启动过程就好了,没错就是这么简单:放开multicast配置这行的注释——给zookeeper这行加上注释——启动!
错误参考:
如果使用multicast报错[DUBBO] Ignore empty notify urls for subscribe url的解决办法。