SpringCloud Alibaba系列——4Dubbo简介与应用(二)
作者 | 一起撸Java
来源 |今日头条
第2章 Dubbo使用
官方案例:
https://github.com/apache/dubbo/tree/3.0/dubbo-demo
2.1 Dubbo初使用
在maven中查看匹配版本
https://mvnrepository.com/artifact/org.apache.dubbo/dubbozookeeper集群搭建教程见zookeeper集群部署讲义
- 构建maven-empty项目dubbo-eclipse2019-demo目录
- 构建三个maven-archetype-quickstart子项目
- dubbo-api
- dubbo-providerrovider
- dubbo-consumer
2.1.1 dubbo-api
1.配置pom
<!-- 增加下面的依赖,后面高级使用会用到参数验证 --><dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version></dependency>
2.dubbo-api提供服务的公共契约,里面提供了对外的服务。
public interface FirstService { //获取返回值 String getFristStr(String str);}
2.1.2 dubbo-provider
1.配置pom
<properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <source.level>1.8</source.level> <target.level>1.8</target.level> <!-- 3.0.2.1版本跟spring5.2.8.release匹配 --> <dubbo.version>3.0.2.1</dubbo.version><!-- spring用这个版本因为有源码注释 --> <spring.version>5.2.8.RELEASE</spring.version> <junit.version>4.13</junit.version> <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version> <skip_maven_deploy>true</skip_maven_deploy> <dubbo.compiler.version>0.0.2</dubbo.compiler.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> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-bom</artifactId> <version>${dubbo.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> </dependency> </dependencies></dependencyManagement><dependencies> <!-- 引入dubbo和zookeeper依赖包 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <type>pom</type> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-metadata-report-zookeeper</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>dubbo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>8.5.23</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jasper</artifactId> <version>8.5.16</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.2.0.Final</version> </dependency></dependencies>
2.在dubbo-provider服务中提供ContactService的实现
@DubboService //@DubboService注解就是服务暴露的注解,想要暴露什么服务就在类上加上该注解public class FirstServiceImpl implements FirstService { @Override public String getContact(String name) { System.out.println("===服务端接收到获取联系方式的请求==="+name); return name+"的联系方式是:111"; }}
3.增加配置类,且加入@EnableDubbo注解即可完成对@DubboService的扫描,如下:
@Configuration//作用 扫描 @DubboService注解 @DubboReference@EnableDubbo(scanBasePackages = "com.example")@PropertySource("classpath:/dubbo-provider.properties")public class ProviderConfiguration {}
4.在resource目录下配置dubbo-provider.properties
dubbo.application.name=dubbo_providerdubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181dubbo.protocol.name=dubbodubbo.protocol.port=20880dubbo.config-center.address=zookeeper://${zookeeper.address:127.0.0.1}:2181
5.在resource目录下增加日志配置log4j.properties(消费端也要增加)
#优先级从高到低依次为:OFF FATAL ERROR WARN INFO DEBUG TRACE ALLlog4j.rootLogger=info, stdout###output to the console###log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.outlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
6.因为注册中心用的是zookeeper,所以还得在本地启动zookeeper服务(如何启动参照zookeeper文章)
7.然后启动服务端服务,将接口注册到zookeeper上去
public class AnnotationProvider { public static void main(String[] args) throws InterruptedException { new AnnotationConfigApplicationContext(ProviderConfiguration.class); System.out.println("---dubbo服务端启动---"); new CountDownLatch(1).await(); }}
2.1.3 dubbo-consumer
1.配置pom
<properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <source.level>1.8</source.level> <target.level>1.8</target.level> <dubbo.version>3.0.2.1</dubbo.version> <spring.version>5.2.8.RELEASE</spring.version> <junit.version>4.12</junit.version> <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.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> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-bom</artifactId> <version>${dubbo.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> </dependency> </dependencies></dependencyManagement><dependencies> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <type>pom</type> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>dubbo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>8.5.23</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jasper</artifactId> <version>8.5.16</version> </dependency> <!-- 日志相关依赖 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.10</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.2.0.Final</version> </dependency></dependencies>
2.增加配置类
@Configuration//@EnableDubbo(scanBasePackages = "com.example")就会扫描@DubboReference注解的属性并且进行属性的依赖注入。@EnableDubbo(scanBasePackages = "com.example")@PropertySource("classpath:/dubbo-consumer.properties")public class ConsumerConfiguration {}
3.在resource目录下配置dubbo-consumer.properties
dubbo.application.name=dubbo_consumerdubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181dubbo.protocol.port=29015dubbo.config-center.address=zookeeper://${zookeeper.address:127.0.0.1}:2181
4.启动消费
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = ConsumerConfiguration.class)public class TestFirstService { @DubboReference private ContactService contactService; @Test public void test(){ System.out.println(contactService.getContact("eclipse2019")); }}
2.1.4 总结
简单总结一下上面的整个过程,其实不难发现,Dubbo这个中间件为我们提供了服务远程通信的解决方案。通过dubbo这个框架,可以开发者快速高效的构建微服务架构下的远程通信实现。
不知道大家是否发现,我们在使用dubbo发布服务,或者消费服务的时候,全程都是采用spring的配置来完成的,这样的好处是我们在学习或者使用dubbo时,如果你用过spring这个框架,那么对于它的学习难度会大大的降低。而且我们也可以看到,dubbo是完全集成Spring 的,因此后续我们去分析dubbo的源码时,还是会有一些和spring有关的内容。
2.2 集成注册中心
Dubbo并不仅仅只是一个RPC框架,他还是一个服务治理框架,它提供了对服务的统一管理、以及服务的路由等功能。
在上面的案例中,我们只是掩饰了Dubbo作为RPC通信的点对点服务,但是就像咱们前面在学习spring cloud的内容一样,服务多了以后,如何管理和维护,以及动态发现呢?
而且,从Dubbo的架构图中可以看到,Dubbo天然就支持服务注册与发现,官方最早推荐的服务注册中心是zookeeper,当然,目前dubbo能够支持的注册中心已经非常多了,比如consul、etcd、nacos、sofa、zookeeper、eureka、redis等等,很显然,Dubbo已经在往一个独立微服务解决方案的生态在发展。
2.2.1 集成zookeeper
集成Zookeeper作为服务注册中心
添加zookeeper的jar包依赖
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type></dependency>
添加注册中心配置,创建dubbo-providerrovider.properties文件用于取代xml中的配置属性,然后用@PropertySource加载该properties配置文件即可 。 dubbo-providerrovider.properties文件内容如下:
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type></dependency>
2.2.2 配置管理
1.配置组件 Dubbo框架的配置项比较繁多,为了更好地管理各种配置,将其按照用途划分为不同的组件,最终所有配置项都会汇聚到URL中,传递给后续处理模块。 常用配置组件如下:
- application: Dubbo应用配置
- registry: 注册中心
- protocol: 服务提供者RPC协议
- config-center: 配置中心
- metadata-report: 元数据中心
- service: 服务提供者配置
- reference: 远程服务引用配置
- provider: service的默认配置或分组配置
- consumer: reference的默认配置或分组配置
- module: 模块配置
- monitor: 监控配置
- metrics: 指标配置
- ssl: SSL/TLS配置
2.配置来源 从Dubbo支持的配置来源说起,默认有6种配置来源: - JVM System Properties,JVM -D 参数
- System environment,JVM进程的环境变量
- Externalized Configuration,外部化配置,从配置中心读取
- Application Configuration,应用的属性配置,从Spring应用的Environment中提取"dubbo"打头的属性集
- API / XML /注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式
- 从classpath读取配置文件 dubbo.properties
3.覆盖关系 下图展示了配置覆盖关系的优先级,从上到下优先级依次降低:
2.3 API的使用
https://dubbo.apache.org/zh/docs/references/configuration/api/
以API 配置的方式来配置你的 Dubbo 应用
通过API编码方式组装配置,启动Dubbo,发布及订阅服务。此方式可以支持动态创建
ReferenceConfig/ServiceConfig,结合泛化调用可以满足API Gateway或测试平台的需要。
- api
public interface ApiService { String getApiServiceStr(String str);}
- 服务提供者
通过ServiceConfig暴露服务接口,发布服务接口到注册中心。
public class ApiServiceImpl implements ApiService { @Override public String getApiServiceStr(String str) { return "api方式调用返回:"+str; } public static void main(String[] args) throws IOException { ApiServiceImpl apiService = new ApiServiceImpl(); //1、应用信息 ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("dubbo-provider-api"); //2、注册信息 RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress("zookeeper://127.0.0.1:2181"); //3、协议信息 ProtocolConfig protocolConfig = new ProtocolConfig(); protocolConfig.setName("dubbo"); protocolConfig.setPort(20881); protocolConfig.setThreads(200); //服务发布 ServiceConfig<ApiService> serviceConfig = new ServiceConfig<>(); serviceConfig.setApplication(applicationConfig); serviceConfig.setRegistry(registryConfig);// 多个注册中心可以用setRegistries() serviceConfig.setProtocol(protocolConfig);// 多个协议可以用setProtocols() serviceConfig.setInterface(ApiService.class); serviceConfig.setRef(apiService);// serviceConfig.setVersion("1.0.0"); serviceConfig.setTimeout(1000000); //暴露及注册服务 serviceConfig.export(); //挂起等待(防止进程退出) System.in.read(); }}
- 服务消费者 通过ReferenceConfig引用远程服务,从注册中心订阅服务接口。
public class ApiTest { @Test public void api(){ // 1、应用信息 ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("dubbo_consumer-api"); //2、注册信息 RegistryConfig registry = new RegistryConfig(); registry.setAddress("zookeeper://127.0.0.1:2181"); //引用API ReferenceConfig<ApiService> referenceConfig = new ReferenceConfig<>(); referenceConfig.setApplication(applicationConfig); referenceConfig.setRegistry(registry); referenceConfig.setInterface(ApiService.class); //服务引用 。这个引用过程非常重,如果想用api方式去引用服务,这个对象需要缓存 ApiService apiService = referenceConfig.get(); System.out.println(apiService.getApiServiceStr("eclipse2019")); }}
- bootstrap 服务发布
public class BootstrapApi { public static void main(String[] args) { new EmbeddedZooKeeper(2181, false).start(); ConfigCenterConfig configCenter = new ConfigCenterConfig(); configCenter.setAddress("zookeeper://127.0.0.1:2181"); // 服务提供者协议配置 ProtocolConfig protocol = new ProtocolConfig(); protocol.setName("dubbo"); protocol.setPort(12345); protocol.setThreads(200); // 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 // 服务提供者暴露服务配置 ServiceConfig<UserService> demoServiceConfig = new ServiceConfig<>(); demoServiceConfig.setInterface(UserService.class); demoServiceConfig.setRef(new UserServiceImpl()); demoServiceConfig.setVersion("1.0.0"); // 第二个服务配置 ServiceConfig<MockService> fooServiceConfig = new ServiceConfig<>(); fooServiceConfig.setInterface(MockService.class); fooServiceConfig.setRef(new MockServiceImpl()); fooServiceConfig.setVersion("1.0.0"); // 通过DubboBootstrap简化配置组装,控制启动过程 DubboBootstrap.getInstance() .application("demo-provider") // 应用配置 .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // 注册中心配置 .protocol(protocol) // 全局默认协议配置 .service(demoServiceConfig) // 添加ServiceConfig .service(fooServiceConfig) .start() // 启动Dubbo .await(); // 挂起等待(防止进程退出) }}
bootstrap 服务发现
public class BootstrapApi { public static void main(String[] args) { // 引用远程服务 ReferenceConfig<UserService> demoServiceReference = new ReferenceConfig<UserService>(); demoServiceReference.setInterface(UserService.class); demoServiceReference.setVersion("1.0.0"); ReferenceConfig<MockService> fooServiceReference = new ReferenceConfig<MockService>(); fooServiceReference.setInterface(MockService.class); fooServiceReference.setVersion("1.0.0"); // 通过DubboBootstrap简化配置组装,控制启动过程 DubboBootstrap bootstrap = DubboBootstrap.getInstance(); bootstrap.application("demo-consumer") // 应用配置 .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // 注册中心配置 .reference(demoServiceReference) // 添加ReferenceConfig .reference(fooServiceReference) .start(); // 启动Dubbo // 和本地bean一样使用demoService // 通过Interface获取远程服务接口代理,不需要依赖ReferenceConfig对象 UserService demoService = DubboBootstrap.getInstance().getCache().get(UserService.class); System.out.println(demoService.queryUser("jack")); MockService fooService = DubboBootstrap.getInstance().getCache().get(MockService.class); System.out.println(fooService.queryArea("1")); }}