dubbo 2.7 的 3种入门案例实战
回顾
大家好,我是老马。
上一节我们一起学习了 。
本文大家一起来学习下 dubbo 的入门案例,共计 3 种方式,总有一款适合你!
Dubbo
Dubbo是一个分布式的高性能RPC框架,可为应用程序提供服务导入/导出功能。
架构
节点角色说明
调用关系说明
服务容器负责启动,加载,运行服务提供者。
服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者在启动时,向注册中心订阅自己所需的服务。
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
这样直接看一遍还是没啥感觉,我们通过 3 种方式的入门案例,加深一下大家的理解。
基于 api 实现
个人理解最简单的 dubbo 入门案例应该是基于 api 的定义实现,因为 dubbo 是完全可以独立于 spring 存在的。
虽然 dubbo 可以和 spring 进行很好的整合,但是最基本的 api 定义显然更容易理解。
pom.xml 定义
引入最基本的依赖
<properties>
<source.level>1.8</source.level>
<target.level>1.8</target.level>
<dubbo.version>2.7.7</dubbo.version>
<junit.version>4.12</junit.version>
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${source.level}</source>
<target>${target.level}</target>
</configuration>
</plugin>
</plugins>
</build>
接口定义
接口作为客户端和服务端之间的约定,如下:
public interface DemoService {
String say();
}
越抽象越简单,意味着越稳定。
一般公司中,服务端系统都会将接口打包上传到公司的私服 neuxs 仓库,便于客户端下载使用。
服务端
服务端针对上面的接口,实现如下:
public class DemoServiceImpl implements DemoService {
@Override
public String say() {
return "hello";
}
}
服务端启动该代码:
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import java.util.concurrent.CountDownLatch;
public class Server {
private static String zookeeperHost = System.getProperty("zookeeper.address", "127.0.0.1");
public static void main(String[] args) throws Exception {
ServiceConfig<DemoService> service = new ServiceConfig<>();
service.setApplication(new ApplicationConfig("first-dubbo-provider"));
service.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
service.export();
System.out.println("dubbo service started");
new CountDownLatch(1).await();
}
}
这里我们依赖了 zookeeper 作为注册中心,你需要首先启动 zookeeper。
zookeeper 入门使用
客户端
客户端和服务端的唯一依赖就是接口,这样以后服务端变更客户端基本可以不关心。
这位分布式系统中的协作开发,提供了极大的便利性。
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
/**
* @author 老马啸西风
* @since 1.0.0
*/
public class Client {
private static String zookeeperHost = System.getProperty("zookeeper.address", "127.0.0.1");
public static void main(String[] args) {
ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
reference.setApplication(new ApplicationConfig("first-dubbo-consumer"));
reference.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
reference.setInterface(DemoService.class);
DemoService service = reference.get();
String message = service.say();
System.out.println(message);
}
}
日志输出如下:
hello
虽说用起来非常简单,但是底层的原理还是相对比价复杂的。我们后续会展开 rpc 手写实现系列,感兴趣的可以关注一波。
spring xml 配置
说明
spring xml 配置曾经风靡一时,我们这里作为经典版本给大家演示一下。
毕竟 dubbo 和 spring 的整合,使用起来才是更加方便。
宝剑配英雄,更能章显威力。
maven 依赖
这次需要和 spring 整合,所以新增了 spring 的相关依赖。
<properties>
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
<source.level>1.8</source.level>
<target.level>1.8</target.level>
<dubbo.version>2.7.7</dubbo.version>
<spring.version>4.3.16.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${source.level}</source>
<target>${target.level}</target>
</configuration>
</plugin>
</plugins>
</build>
接口定义和实现
和上面一样,此处不再赘述。
内嵌 zk
这里官方 demo 引入了一个内嵌的 zk 类 EmbeddedZooKeeper
,这样基本的学习演示,就可以不用下载 apache zookeeper 了。
服务端
服务端作为服务的提供者,声明如下:
public class BasicProvider {
public static void main(String[] args) throws Exception {
new EmbeddedZooKeeper(2181, false).start();
// wait for embedded zookeeper start completely.
Thread.sleep(1000);
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml");
context.start();
System.out.println("dubbo service started");
new CountDownLatch(1).await();
}
}
其中 dubbo-demo-provider.xml
是 xml 配置,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder/>
<dubbo:application name="demo-provider"/>
<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
<bean id="demoService" class="com.github.houbb.dubbo.learn.basic.DemoServiceImpl"/>
<dubbo:service interface="com.github.houbb.dubbo.learn.basic.DemoService" ref="demoService"/>
</beans>
客户端
实现如下:
package com.github.houbb.dubbo.learn.basic;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BasicConsumer {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml");
context.start();
DemoService demoService = (DemoService) context.getBean("demoService");
String hello = demoService.say();
System.out.println(hello);
}
}
其中 dubbo-demo-consumer.xml
的实现如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder/>
<dubbo:application name="demo-consumer"/>
<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
<dubbo:reference id="demoService" check="true" interface="com.github.houbb.dubbo.learn.basic.DemoService"/>
</beans>
测试
首先启动服务端,然后启动客户端。
启动客户端时报错如下:
[DUBBO] qos-server can not bind localhost:22222, dubbo version: 2.6.4, current host: 169.254.68.252
java.net.BindException: Address already in use: bind
[DUBBO] Fail to start qos server: , dubbo version: 2.6.4, current host: 169.254.68.252
java.net.BindException: Address already in use: bind
问题原因
Qos=Quality of Service,qos是Dubbo的在线运维命令,可以对服务进行动态的配置、控制及查询。
consumer启动时qos-server也是使用的默认的22222端口,但是这时候端口已经被provider给占用了,所以才会报错的。
解决方案
我们将 dubbo-demo-consumer.xml
application 配置进行调整,指定一个不同的端口即可。
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="demo-consumer">
<dubbo:parameter key="qos.enable" value="true" />
<dubbo:parameter key="qos.accept.foreign.ip" value="false" />
<dubbo:parameter key="qos.port" value="33333" />
</dubbo:application>
重新启动测试通过。
注解版本
说明
个人最喜欢的还是注解版本,实现起来更加优雅。
定义
接口定义和内嵌的 zk 和上面一样,不再赘述。
服务端
代码
注意,这里使用 @DubboService
修饰实现类。
package com.github.houbb.dubbo.learn.annotation.provider;
import com.github.houbb.dubbo.learn.annotation.api.DemoService;
import org.apache.dubbo.config.annotation.DubboService;
/**
* @author 老马啸西风
* @since 1.0.0
*/
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String say() {
return "hello";
}
}
服务端配置类:
package com.github.houbb.dubbo.learn.annotation.provider;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* @author binbin.hou
* @since 1.0.0
*/
@Configuration
@EnableDubbo(scanBasePackages = "com.github.houbb.dubbo.learn.annotation.provider")
@PropertySource("classpath:dubbo-provider.properties")
public class ProviderConfiguration {
}
这里通过 @EnableDubbo
执行扫包操作。
dubbo-provider.properties 配置
内容如下:
dubbo.application.name=annotation-provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
客户端
package com.github.houbb.dubbo.learn.annotation.consumer;
import com.github.houbb.dubbo.learn.annotation.api.DemoService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;
/**
* @author 老马啸西风
* @since 1.0.0
*/
@Component
public class AnnotationAction {
@DubboReference
private DemoService demoService;
public String say() {
return demoService.say();
}
}
这里通过 @DubboReference
注解注入依赖的服务。
客户端配置注解如下:
package com.github.houbb.dubbo.learn.annotation.consumer;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* @author 老马啸西风
* @since 1.0.0
*/
@Configuration
@EnableDubbo(scanBasePackages = "com.github.houbb.dubbo.learn.annotation.client")
@PropertySource("classpath:dubbo-consumer.properties")
@ComponentScan(value = {"com.github.houbb.dubbo.learn.annotation.consumer"})
public class ConsumerConfiguration {
}
其中 dubbo-consumer.properties
配置如下:
# dubbo-consumer.properties
dubbo.application.name=annotation-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.consumer.timeout=3000
测试
启动服务端
package com.github.houbb.dubbo.learn.annotation;
import com.github.houbb.dubbo.learn.annotation.provider.ProviderConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.concurrent.CountDownLatch;
public class AnnotationProviderBootstrap {
public static void main(String[] args) throws Exception {
new EmbeddedZooKeeper(2181, false).start();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.out.println("dubbo service started.");
new CountDownLatch(1).await();
}
}
日志如下:
dubbo service started.
启动客户端
package com.github.houbb.dubbo.learn.annotation;
import com.github.houbb.dubbo.learn.annotation.consumer.AnnotationAction;
import com.github.houbb.dubbo.learn.annotation.consumer.ConsumerConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationConsumerBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start();
final AnnotationAction annotationAction = (AnnotationAction) context.getBean("annotationAction");
System.out.println("hello : " + annotationAction.say());
}
}
日志如下:
hello : hello
小结
本次的 dubbo 入门实战到这里就告一段落了。
dubbo 让远程服务调用起来像本地一样自然,和 spring 整合为我们提供了更大的编程便利性。
后续我们将和大家一起实现属于自己的 RPC 框架,感兴趣的小伙伴可以关注一波,实时获得最新消息。
希望本文对你有所帮助,如果喜欢,欢迎点赞收藏转发一波。
我是老马,期待与你的下次相遇。