RPC框架初體驗之Dubbo
版本描述:dubbo 2.7.2
Dubbo是阿里開源的一款RPC框架,最近在學習微服務的時候有提及到。因此對Dubbo進行了入門級體驗,這裏主要體驗體驗Dubbo的幾種配置方式,如XML配置、API配置、註解配置,以及Springboot裏整合Dubbo,同時體驗幾種註冊中心,如simple、zk、redis、multicast。
Dubbo官網內容還是很豐富的,支持中文。地址:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html
1 Dubbo配置使用
1.1 基於原生API的配置
官網文檔:http://dubbo.apache.org/zh-cn/docs/user/configuration/api.html
怎麼說呢,參考官網這個文檔實現時踩了不少坑,因爲官網提供的註冊中心沒法使用,又是初次接觸,走了不少彎路,而自己又是直腸子一根,非要自己實現一個註冊中心,然後參考官網給的Simple註冊中心的例子,有兩點逼得我強迫症犯了,首先使用的是XML配置的方式創建註冊中心服務,而我這裏只想通過原生API實現,另一個
<!-- 簡單註冊中心實現,可自行擴展實現集羣和狀態同步 -->
<bean id="registryService" class="org.apache.dubbo.registry.simple.SimpleRegistryService" />
這裏面提到的org.apache.dubbo.registry.simple.SimpleRegistryService這個類,我死活找不到。就這倆問題糾結了一天。後來終於解決了,在github上dubbo源碼的測試文件裏找到了。心裏一萬匹cnm在奔騰。迴歸正題,使用原生API的方式配置其實就是自己創建實例,傳入配置參數,啓動服務。下面將一步步講解。
1.1.1 項目準備
首先創建一個名爲dubbo-demo-api的模塊,然後再該模塊下創建三個子模塊
dubbo-demo-api/
├── dubbo-demo-api-api
├── dubbo-demo-api-consumer
├── dubbo-demo-api-provider
└── pom.xml
- dubbo-demo-api-api:提供演示接口
- dubbo-demo-api-consumer:服務消費者
- dubbo-demo-api-provider:服務提供者
1.1.2 dubbo-demo-api-api 模塊
該模塊主要提供用來演示的接口,在learn.demo.dubbo.api.api包下創建DemoService接口,如下所示
package learn.demo.dubbo.api.api;
/**
* Created by shirukai on 2019-06-20 09:23
* DemoService 接口
*/
public interface DemoService {
String sayHello(String name);
}
1.1.3 dubbo-demo-api-provider模塊
該模塊是創建dubbo提供者服務。首先要引入dubbo相關依賴
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
然後引入api模塊
<dependency>
<groupId>learn.demo</groupId>
<artifactId>dubbo-demo-api-api</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
1.1.3.1 實現DemoService接口
上面我們在api模塊中定義的DemoService接口,這裏我們在learn.demo.dubbo.api.provider這個包下實現該接口。創建名爲DemoServiceImpl的類,內容如下:
package learn.demo.dubbo.api.provider;
import learn.demo.dubbo.api.api.DemoService;
/**
* Created by shirukai on 2019-06-20 09:25
* DemoService接口實現
*/
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "This service base in API.\nHello " + name;
}
}
1.1.3.2 實現Simple註冊中心
這裏在實現Provider之前,先實現以下Simple註冊中心,之前也有講到官網在講Simple註冊中心的時候,是使用Spring的XML配置去生成Bean然後創建服務的,而且裏面的提到的SimpleRegistryService類也找不到,經過九九八十一難這裏使用API去實現一個Simple註冊中心。這裏需要幾個類:AbstractRegistryService,SimpleRegistryExporter,SimpleRegistryService。這幾個類可以從dubbo的github上找到,https://github.com/apache/dubbo/tree/master/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo。
我們可以在自己的項目裏,創建 org.apache.dubbo.registry包,然後將這三個類複製進去。
在learn.demo.dubbo.api.provider包下創建SimpleRegistryServiceProvider類用來提供註冊中心服務,代碼如下:
package learn.demo.dubbo.api.provider;
import org.apache.dubbo.registry.SimpleRegistryExporter;
/**
* Created by shirukai on 2019-06-20 09:32
* <p>
* 簡單註冊中心服務提供者
* 基於RegistryService接口實現的簡單註冊中心
* 代碼位置:
* https://github.com/apache/dubbo/tree/master/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo
*/
public class SimpleRegistryServiceProvider {
public static void main(String[] args) throws Exception {
// 暴露註冊中心服務,端口爲9090
SimpleRegistryExporter.export(9090);
// 任意輸入退出
System.in.read();
}
}
1.1.3.3 實現DemoServiceProvider
使用Dubbo的原生API實現生產者,大體流程:
- 創建應用配置ApplicationConfig,我們可以設置應用名稱、設置qos端口等等。
- 創建註冊中心配置RegistryConfig,可以設置註冊中心類型,地址,端口,用戶名,密碼等。
- 創建服務配置ServiceConfig,此實例很重要,有與註冊中心的連接
- 暴露服務export
內容如下:
package learn.demo.dubbo.api.provider;
import learn.demo.dubbo.api.api.DemoService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
/**
* Created by shirukai on 2019-06-20 09:30
* <p>
* DemoService 生產者
* 該Demo註冊中心使用自定義註冊中心,SimpleRegistryService
* 所以在啓動該服務之前,需要先啓動註冊中心
*/
public class DemoServiceProvider {
public static void main(String[] args) throws Exception {
// 應用配置
ApplicationConfig applicationConfig = new ApplicationConfig("api-demo-service-provider");
// qos 默認端口22222在本地同時啓動多個服務時,需要手動修改
applicationConfig.setQosPort(22222);
// 註冊中心配置
RegistryConfig registryConfig = new RegistryConfig("127.0.0.0:9090");
// 服務配置,此實例很重,封裝了與註冊中心的連接,請自行緩存,否則可能造成內存和連接泄漏
ServiceConfig<DemoService> service = new ServiceConfig<>();
service.setApplication(applicationConfig);
service.setRegistry(registryConfig);
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
// 暴露服務
service.export();
// 輸入任意退出
System.in.read();
}
}
1.1.4 dubbo-demo-api-consumer模塊
該模塊dubbo服務消費者,依然需要引入dubbo和自定義api的jar包。
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>learn.demo</groupId>
<artifactId>dubbo-demo-api-api</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
consumer的實現與provider步驟類似
- 創建應用配置ApplicationConfig
- 創建配置中心配置RegistryConfig
- 創建服務ReferenceConfig
- 獲取接口實例
代碼如下:
package learn.demo.api.consumer;
import learn.demo.dubbo.api.api.DemoService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
/**
* Created by shirukai on 2019-06-20 09:53
* DemoService 消費者
*/
public class DemoServiceConsumer {
public static void main(String[] args) {
// 應用配置
ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-api-consumer");
applicationConfig.setQosPort(22223);
// 配置註冊中心
RegistryConfig registryConfig = new RegistryConfig("127.0.0.1:9090");
ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
reference.setApplication(applicationConfig);
reference.setRegistry(registryConfig);
reference.setInterface(DemoService.class);
// 獲取服務
DemoService service = reference.get();
// 服務調用
String message = service.sayHello("dubbo !");
System.out.println(message);
}
}
1.2 基於XML的配置
上面我們介紹了使用API進行Dubbo的配置,該中方式方便集成其它系統,但是實現繁瑣。所以官方提供了Spring基於XML的配置方式,該配置方式依賴於Spring,是加載Bean的方式創建服務。官網文檔:http://dubbo.apache.org/zh-cn/docs/user/configuration/xml.html
1.2.1 項目準備
首先創建一個名爲dubbo-demo-xml的模塊,然後再該模塊下創建三個子模塊
dubbo-demo-xml/
├── dubbo-demo-xml-api
├── dubbo-demo-xml-consumer
├── dubbo-demo-xml-provider
└── pom.xml
- dubbo-demo-xml-api:提供演示接口
- dubbo-demo-xml-consumer:服務消費者
- dubbo-demo-xml-provider:服務提供者
1.2.2 dubbo-demo-xml-api模塊
與dubbo-demo-api-api相同。
1.2.3 dubbo-demo-xml-provider模塊
同上引入api以及dubbo依賴。
1.2.3.1 DemoServiceImpl
實現定義的api接口。
package learn.demo.dubbo.xml.provider;
import learn.demo.dubbo.xml.api.DemoService;
/**
* Created by shirukai on 2019-06-20 10:19
* 實驗DemoService接口
*/
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "This service base in XML.\nHello " + name;
}
}
1.2.3.2 dubbo-provider.xml
在resource/spring下創建dubbo-provider.xml配置文件,用來配置dubbo的provider服務。具體參數參考官網。
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- provider's application name, used for tracing dependency relationship -->
<dubbo:application name="demo-xml-provider">
<!-- 指定qos端口,配置優先級低於dubbo.properties-->
<dubbo:parameter key="qos.port" value="22222"/>
</dubbo:application>
<!-- 基於廣播的註冊中心 -->
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<!-- use dubbo protocol to export service on port 20880 -->
<dubbo:protocol name="dubbo"/>
<!-- service implementation, as same as regular local bean -->
<bean id="demoService" class="learn.demo.dubbo.xml.provider.DemoServiceImpl"/>
<!-- declare the service interface to be exported -->
<dubbo:service interface="learn.demo.dubbo.xml.api.DemoService" ref="demoService"/>
</beans>
1.2.3.3 DemoServiceProvider
Provider實現比較簡單,使用ClassPathXmlApplicationContext從xml獲取應用上下文,然後啓動。
package learn.demo.dubbo.xml.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by shirukai on 2019-06-20 10:18
* 基於XML的Dubbo服務提供者
*/
public class DemoServiceProvider {
public static void main(String[] args) throws Exception {
// 從XML配置文件中獲取應用上下文
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-provider.xml");
context.start();
System.in.read();
}
}
1.2.4 dubbo-demo-xml-consumer模塊
同上需在pom中引入api和dubbo依賴。
1.2.4.1 dubbo-consumer.xml
使用xml配置consumer服務。在resource/spring下創建dubbo-consumer.xml,內容如下
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<dubbo:application name="demo-xml-consumer"/>
<!-- 使用廣播註冊中心 -->
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<!-- generate proxy for the remote service, then demoService can be used in the same way as the
local regular interface -->
<dubbo:reference id="demoService" check="false" interface="learn.demo.dubbo.xml.api.DemoService"/>
</beans>
1.2.4.2 DemoServiceConsumer
使用ClassPathXmlApplicationContext獲取應用上下文,並在上下文中獲取DemoService接口對應的Bean,然後調用接口方法。
package learn.demo.dubbo.xml.consumer;
import learn.demo.dubbo.xml.api.DemoService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by shirukai on 2019-06-20 11:07
* 基於XML的Dubbo服務消費之
*/
public class DemoServiceConsumer {
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml");
context.start();
DemoService demoService = context.getBean("demoService", DemoService.class);
String message = demoService.sayHello("world");
System.out.println(message);
}
}
1.2.4.3 補充,關於dubbo的配置
dubbo的配置,我們可以通過dubbo.properties文件來配置,如我要修改qos端口,可以只創建dubbo.properites文件,然後添加如下配置:
# dubbo相關配置文件
dubbo.application.qos.port=22223
1.3 基於註解的配置
官網:http://dubbo.apache.org/zh-cn/docs/user/configuration/annotation.html
dubbo關於註解的配置,與xml如出一轍,只不過我們不需要配置xml了,在需要暴露的接口實現類上添加@Service註解,然後通過@Configuration將相關配置注入到Spring裏。
1.3.1 項目準備
首先創建一個名爲dubbo-demo-xml的模塊,然後再該模塊下創建三個子模塊
dubbo-demo-annotation/
├── dubbo-demo-annotation-api
├── dubbo-demo-annotation-consumer
├── dubbo-demo-annotation-provider
└── pom.xml
- dubbo-demo-annotation-api:提供演示接口
- dubbo-demo-annotation-consumer:服務消費者
- dubbo-demo-annotation-provider:服務提供者
1.3.2 dubbo-demo-annotation-api模塊
跟dubbo-demo-api-api模塊相同。
1.3.3 dubbo-demo-annotation-provider模塊
1.3.3.1 DemoServiceImpl
同上,實現DemoService接口,但是需要使用@Service來標記該實現類要通過Provider暴露服務。
package learn.demo.dubbo.annotation.provider;
import lear.demo.dubbo.annotation.api.DemoService;
import org.apache.dubbo.config.annotation.Service;
/**
* Created by shirukai on 2019-06-20 14:04
* DemoService實現類
*/
@Service
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "The service base in Annotation.\nHello" + name;
}
}
1.3.3.2 dubbo-provider.properties
通過dubbo-provider.properties來對dubbo的provider進行相應的配置。在resource/spring下創建dubbo-provider.properties文件,內容如下
dubbo.application.name=dubbo-demo-annotation-provider
dubbo.application.qos.port=22222
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
1.3.3.3 DemoServiceProvider
與xml配置相同,需要獲取應用上下文,只不過使用AnnotationConfigApplicationContext來獲取,並且需要將dubbo的配置通過@Configuration形式注入到Spring,並制定需要掃面的包路徑,以及配置文件所在路徑。內容如下:
package learn.demo.dubbo.annotation.provider;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* Created by shirukai on 2019-06-20 14:06
* DemoService提供者
*/
public class DemoServiceProvider {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "learn.demo.dubbo.annotation.provider")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("multicast://224.5.6.7:1234");
return registryConfig;
}
}
}
1.3.4 dubbo-demo-annotation-consumer模塊
1.3.4.1 dubbo-consumer.properties
通過dubbo-consumer.properties來配置dubbo的consumer的相關配置,如服務名稱、註冊中心地址等
dubbo.application.name=dubbo-demo-annotation-consumer
dubbo.registry.address=multicast://224.5.6.7:1234
1.3.4.2 DemoServiceComponent
通過@Component創建DemoService組件,並通過@Reference注入遠程Dubbo提供的接口實例。
package learn.demo.dubbo.annotation.consumer.comp;
import lear.demo.dubbo.annotation.api.DemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Component;
/**
* Created by shirukai on 2019-06-20 14:22
* DemoService 組件
*/
@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
@Reference
private DemoService demoService;
@Override
public String sayHello(String name) {
return demoService.sayHello(name);
}
}
1.3.4.3 DemoServiceConsumer
通過@Configuration注入dubbo相關配置,並通過AnnotationConfigApplicationContext獲取應用上下文。
package learn.demo.dubbo.annotation.consumer;
import lear.demo.dubbo.annotation.api.DemoService;
import learn.demo.dubbo.annotation.consumer.comp.DemoServiceComponent;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* Created by shirukai on 2019-06-20 14:10
* DemoService消費者
*/
public class DemoServiceConsumer {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start();
DemoService service = context.getBean("demoServiceComponent", DemoServiceComponent.class);
String message = service.sayHello("world");
System.out.println(message);
}
@Configuration
@EnableDubbo(scanBasePackages = "learn.demo.dubbo.annotation.consumer.comp")
@PropertySource("classpath:/spring/dubbo-consumer.properties")
@ComponentScan(value = {"learn.demo.dubbo.annotation.consumer.comp"})
static class ConsumerConfiguration {
}
}
2 SpringBoot整合Dubbo
SpringBoot整合Dubbo簡潔的不能再簡潔,不需要額外的配置,只需要引入幾個依賴包即可。
2.1 項目準備
首先創建一個名爲dubbo-demo-springboot的模塊,然後再該模塊下創建三個子模塊
dubbo-demo-springboot/
├── dubbo-demo-springboot-api
├── dubbo-demo-springboot-consumer
├── dubbo-demo-springboot-provider
└── pom.xml
- dubbo-demo-springboot-api:提供演示接口
- dubbo-demo-springboot-consumer:服務消費者
- dubbo-demo-springboot-provider:服務提供者
2.2 dubbo-demo-springboot-api模塊
與之前api模塊一樣,定義DemoService接口。
2.3 dubbo-demo-springboot-provide模塊
2.3.1 引入依賴
因爲此項目是springboot項目,這裏將springboot模塊添加到parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
引入springboot starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
引入dubbo springboot starter
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.1</version>
</dependency>
引入dubbo依賴
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
引入api依賴
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
2.3.2 application.properties
在resource創建application.properties配置文件,裏面添加dubbo相應配置
spring.application.name=dubbo-spring-boot-provider
# dubbo
dubbo.scan.base-packages=learn.demo.dubbo.springboot.provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=12345
dubbo.registry.address=multicast://224.5.6.7:1234
2.3.3 DemoServiceImpl
實現DemoService接口,並使用dubbo的@Service註解標記此類爲dubbo暴露的服務實例
package learn.demo.dubbo.springboot.provider;
import learn.demo.dubbo.springboot.api.DemoService;
import org.apache.dubbo.config.annotation.Service;
/**
* Created by shirukai on 2019-06-20 15:08
*/
@Service(version = "1.0.0")
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "The service of dubbo from springboot.\nHello " + name;
}
}
2.3.4 DemoServiceProvider
Dubbo 服務提供實現,主要啓動SpringBoot即可。
package learn.demo.dubbo.springboot.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Created by shirukai on 2019-06-20 15:08
*/
@SpringBootApplication
public class DemoServiceProvider {
public static void main(String[] args) {
SpringApplication.run(DemoServiceProvider.class, args);
}
}
2.4 dubbo-demo-springboot-consumer模塊
2.3.1 引入依賴
與provider一樣,引入springboot-starter、dubbo-spring-boot-starter、dubbo、api依賴。另外這裏提供了一個REST接口,所以需要引入web服務相關的依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.3.2 application.properties
spring.application.name=dubbo-spring-boot-consumer
# dubbo
dubbo.scan.base-packages=learn.demo.dubbo.springboot.consumer
dubbo.registry.address=multicast://224.5.6.7:1234
2.3.4 DemoController
提供一個REST接口,並調用RPC服務
package learn.demo.dubbo.springboot.consumer.controller;
import learn.demo.dubbo.springboot.api.DemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by shirukai on 2019-06-20 16:03
*/
@RestController
public class DemoController {
@Reference(version = "1.0.0")
private DemoService demoService;
@GetMapping(value = "/sayHello")
public String sayHello(@RequestParam("name") String name) {
return demoService.sayHello(name);
}
}
2.3.5 DemoServiceConsumer
Dubbo Consumser服務啓動,,正常啓動SpringBoot即可。
package learn.demo.dubbo.springboot.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Created by shirukai on 2019-06-20 16:00
*/
@SpringBootApplication
public class DemoServiceConsumer {
public static void main(String[] args) {
SpringApplication.run(DemoServiceConsumer.class, args);
}
}