Dubbo简介

574 篇文章 4 订阅
272 篇文章 1 订阅
                          第1章   远程调用  

1.1 访问网络上的接口

1.1.1 互联网服务

天气接口:
中国天气网地址:http://www.weather.com.cn
请求地址:http://www.weather.com.cn/data/sk/101110101.html
101010100=北京
101020100=上海
101210101=杭州
京东万象: https://wx.jcloud.com/api
聚合数据:https://www.juhe.cn/

1.2 公司内部提供的服务

一家对外提供服务的公司,例如百度,腾讯,阿里,京东,58                              同城等,公司内部有多 

个事业群,事业部门,每个事业部门内部又有若干个子部门,子部门里面有多个不同的小组
负责各自的业务。提供对外的服务。
公司内部,外部提供的服务不仅多,而且细分,还有交叉的情况。
前面的例子是访问互联网上的服务,使用的是 http 请求网络资源。相对来说访问服务
方式单一,处理服务的效率相对较低。公司内部服务之间可以使用多种不同的方式访问服务。

1.2.1 使用单一应用访问天气服务

图二:

A 、 新建web 项目 01-weathService

项目结构:

B、 新建数据类Weather

重写toString()

C、 定义Service 接口

D、 定义Service 接口的实现类

E、 定义Servlet ,提供访问地址

F、 定义访问添加服务的jsp

首先加入jQuery 库文件,放到项目的 js 目录下

index.jsp

G、 执行web 应用

1.2.2 使用独立应用提供天气服务

(1) 独立的应用提供服务

在一台或多台物理机器上,运行的独立应用程序,供多个客户端访问天气服务。

A 、 把01-weatherService 应用复制,名称02-companyProviderWeather

B、 去掉js 文件夹,index.jsp 文件

C、 使用Servlet 提供服务

(2) 在独立的应用中访问天气服务

在一台独立的计算上, 通过应用访问天气服务。

A 、 把01-weatherService 应用复制,名称03-companyConsumeWeather

B、 去掉src 目录下的java 代码

C、 修改index.jsp 中的访问服务Servlet 的地址

D、 运行应用

发布两个应用到 tomat 服务器。 03-companyConsumeWeather 应用访问
02-companyProviderWeather 提供的服务。 两个应用是独立部署到不同的机器, 使用两个
或多个计算提供计算能力。
1.3 远程调用

1.3.1 远程调用涉及的概念

(1) 协议

  协议指多方共同遵循的规范,在网络中的计算机进行数据交换依靠各种协议。例如http,  

ftp 等。
一台计算机按规定好的格式发送数据,另一台计算的程序按指定的格式接收数据,两台
计算使用互相理解的格式读写数据。达到数据交换的目的。

(2) RPC-远程过程调用协议

RPC 是什么?
PRC 是Remote Procedure Call Protocol ,称为:远程过程调用协议。是一种通过网络从
远程计算机程序上请求服务,而不需要了解底层网络技术的协议。该协议允许运行于一台计
算机的程序调用另一台计算机的程序。程序员无需编为网络交互功能编码。

RPC 的作用?
主要功能是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本
地调用的语义简洁性。在一台计算的程序使用其他计算机上的功能就是使用自己的功能一样。
RPC 技术提供了透明的访问其他服务的底层实现细节。使用分布式系统中的服务更加方便。

分布式?
分布式指多台计算机位于网络系统中,多台计算给形成一个整体对外界提供服务。用户
使用系统不知道是多台计算机,使用不同的操作系统,不同的应用程序提供服务。

                                        第2章    Dubbo  

2.1 Dubbo 介绍

  官网:http://dubbo.io/  

                                                                                                                       

  红色框文字翻译后:一个高性能的,基于java  的,开源RPC 框架。  
    

  Dubbo 是一个框架  
  Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的RPC 远程服务调用方案、服 

务治理方案。
Dubbo 是阿里巴巴服务化治理方案的核心框架,每天为 2,000+ 个服务提供
3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点:

已知的使用企业:

2.1.1 其他的RPC 框架

⚫ 新浪微博的Motan (https://github.com/weibocom/motan)
⚫ Dubbox 是由当当对阿里的 Dubbo 的升级,可以被视为 Dubbo 的增强版
https://github.com/dangdangdotcom/dubbox
⚫ 国外的有google grpc
前两个是基于java 语言的和spring 集成在一起的, grpc 是跨语言的,使用面更广。

2.1.2 Dubbo 能做什么

⚫ 实现透明的远程方法调用,就像调用本地方法一样。可以忽略远程调用的实现细节。简
单配置即可使用。
⚫ 服务的自动注册和服务发现。通过注册中心,服务实现动态管理(增减服务方)。调用
服务的消费者无需写死调用地址。
⚫ 软件的负载均衡实现和容错机制,无需使用硬件。降低成本。

2.1.3 Dubbo 服务的实现原理

Dubbo 的底层实现是动态代理,   由Dubbo 框架创建远程服务(接口)对象的代理对象, 

通过代理对象调用远程方法。
2.2 Dubbo 支持的协议

 支持8 种协议:dubbo ,    hessian , rmi , http, webservice , thrift , memcached , redis。  

dubbu 官方推荐使用dubbo 协议。dubbo 协议默认端口20880

2.2.1 Ddubbo 协议

A 、 Dubbo 协议特点

Dubbo 协议采用单一长连接和异步通讯,适合于小数据量大并发的服务调用,以及服务消费
者机器数远大于服务提供者机器数的情况。

B、 网络通信

Dubbo 协议底层网络通信默认使用的是netty,性能非常优秀,官方推荐使用

C、 不适合的地方

Dubbo 协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低

D、 使用Dubbo 协议

<dubbo:protocol name=“dubbo” port=“20880” />

2.2.2 长连接和短连接

Dubbo 协议使用的长连接:

短链接:
长连接和短连接接:

 所谓长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有 

数据包发送,需要双方发检测包。短连接是指通讯双方有数据交互时,就建立一个连接,数

据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。

 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。例如:数据库的 

连接用长连接。像Web 网站的http 服务一般都用短链接,因为长连接对于服务端来说会耗

费一定的资源,而像Web 网站频繁的用,使用短连接会更省一些资源,并发量大,但每个

用户无需频繁操作情况下需用短连好。

2.3 Dubbo 的组件

2.4 使用Dubbo 的第一个项目

 点对点的直连项目:消费者直接访问服务提供者,没有注册中心。消费者必须指定服务 

提供者的访问地址(url)。

2.4.1 服务提供者(在web 容器中使用)

服务提供者开发步骤:

⚫ 定义服务接口 (该接口需单独打包,在服务提供方和消费方共享)

⚫ 在服务提供方实现接口 (对服务消费方隐藏实现)

⚫ 用Spring 配置声明暴露服务

⚫ 加载Spring 配置 (创建bean)

项目结构:

A 、 新建web 项目,命名:04-dubboProviderService

注意:1)选择Tomcat 作为服务器。 2) 生成web.xml 文件.

B、 导入jar

dubbo.jar: Dubbo 框架的实现
javaassist-3.15.0-GA.jar:字节码生成jar

netty-3.2.5.Final.jar:网络传输

spring-*.jar: Dubbo 是基于spring 的。配置bean。

C、 定义表示天气信息的对象Weather

重写的toString()

不实现Serializable 接口的错误提示:

D、 定义服务的接口(面向接口编程)

E、 定义天气接口的实现类

包名:package com.bjpowernode.service.provider

F、 编写Spring 配置文件,Spring 作为容器管理对象

第一步:加入:dubbo.xsd 约束文件

第二步:本机配置代码提示:eclipse 菜单Windows-→Preferences

第三步:声明服务定义
dubbo:application :定义服务名称,一般使用项目名。
dubbo:service:声明服务,暴露给消费者使用。
bean:定义服务的实现类,提供服务的代码实现。spring 中的标签
G、 新建测试类:MyTest 测试配置文件,对象定义等是否正确。

H、 修改web.xml 文件,web 应用中使用Spring

服务提供者的功能实现完成。

I、 导出服务接口

服务接口要给消费者使用,需要把接口定义打成jar .
第一步:eclipse 菜单 File — Export

第二步:导出接口
第三步:查看导出的jar 文件
使用winrar 等压缩软件查看。

2.4.2 服务消费者

(1) 直接使用远程服务提供者对象

服务消费者项目可以是j2se, j2ee 等项目类型,使用服务。

服务消费者开发步骤:

⚫ 通过Spring 配置引用远程服务

⚫ 加载Spring 配置,并调用远程服务:(也可以使用IoC 注入)

项目结构:

A 、 新建java project ,命名 04-dubboConsume

B、 导入jar

工程根目录下,新建 libs ,存放 jar 。这个项目是非 web 应用,不需要 spring-web.jar,
spring-webmvc.jar 。 必须导入服务提供者的jar 。 上面步骤导出的dubbo-weather-provider.jar

C、 新建天气信息类Weacher,结构同服务提供者项目中的Weacher

可以拷贝服务提供者类中的Weather, 或者服务提供者导出接口的同时,把Weather 类和接

口一同导出到dubbo-weather-provider.jar

重写的toString()

D、 新建配置文件 dubbo-consume.xml

配置文件需要加入spring 和dubbo 的约束文件, 同服务提供者的provider.xml 的操作方式。

E、 定义测试类,访问远程服务

F、 测试访问远程服务

首先启动,服务提供者。服务提供者05-ProviderService 是web 应用发布到tomcat 上运行
然后再运行Consume 程序。

加入:

输出:

(2) 注入方式使用远程服务对象。

A 、 新建使用远程服务对象的Service

B、 修改dubbo-consume.xml 声明ShowWeatherService 对象,注入服务提供者

对象

C、 测试类

2.5 使用接口作为独立项目

  公司或者企业有很多的服务,这些服务有不同的部门,不同的人员管理,维护。例如公 

司做生活服务类业务的,提供类似58 同城的业务。其中公共服务部门负责提供天气资讯和
影视资讯两个内容。A 小组两个人负责天气资讯;B 小组三个人负责影视资讯。现在需要在
公司的网站同时提供两种资讯。你作为网站开发人员需要使用 A 和 B 两个小组不同服务内
容。使用A 组,B 组的两个服务提供者接口。

图一:

公司使用Dubbo 管理服务,A 组,B 组分别各自服务的接口的jar 包。比如 A-Weather.jar ,
B-Movie.jar . 网站的开发人员需要同时维护两个jar 。任何一个有改动,都需要做调整代码。

图二:

现在只要使用公共服务部门提供的一个服务接口jar 包就可以了。

2.5.1 服务提供者接口定义

A 、 新建Java Project 项目:05-ProviderInteface

Java 项目,只定义接口,无需导入jar 。

B、 新建天气信息的数据类Weatcher

重写的toString()

C、 新建天气服务接口

D、 新建影视信息的数据类Movie

重新toString()

E、 新建影视服务接口

F、 导出包含所有接口的jar

导出jar ,选择eclipse 菜单File ---- > Export
G、 查看导出的jar 内容

2.5.2 服务提供者接口实现

A 、 新建web 工程 05-ProviderInterfaceImpl,生成web.xml

项目结构:

B、 导入dubbo,spring,服务接口的jar

C、 新建实现WeatherService 接口的实现类

D、 新建实现MovieService 接口的实现类

E、 新建spring 配置文件dubbo-provider.xml

F、 修改web.xml ,增加ContextLoaderListener 监听器

2.5.3 服务消费者

A 、 新建Java Project:05-ConsumeService

项目结构:

B、 导入dubbo,spring,服务提供者接口jar
C、 新建spring 配置文件dubbo-consume.xml

D、 定义访问服务的测试类

服务提供者实现项目06-ProviderInterfaceImpl 是web 项目,先发布到tomcat ,启动应用。在
执行UseServiceClient.查看访问结果。

2.6 dubbo 常用标签

Dubbo 中常用标签。分为三个类别:公用标签,服务提供者标签,服务消费者标签

2.6.1 公用标签

dubbo:application/ 和 dubbo:registry/

A、 配置应用信息

<dubbo:application name=”服务的名称”/>

B、 配置注册中心

<dubbo:registry address=”ip:port” protocol=”协议”/>

2.6.2 服务提供者标签

A 、 配置访问服务提供者的协议信息

<dubbo:protocol name=”dubbo” port=”20880”/>

B、 配置暴露的服务

<dubbo:service interface=”服务接口名” ref=”服务实现对象bean”>

2.6.3 服务消费者

A 、 配置服务消费者引用远程服务

<dubbo:reference id=”服务引用 bean 的 id” interface=”服务接口名”/>

2.7 常用配置项目

check , retries 等

2.7.1 关闭检查check

   Dubbo      缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 

初始化完成,以便上线时,能及早发现问题,默认check=true 。通过check="false"关闭检查,
比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
例1:关闭某个服务的启动时检查
<dubbo:reference interface=“com.foo.BarService” check=“false” />
例2:关闭注册中心启动时检查
<dubbo:registry check=“false” />

   默认启动服务时检查注册中心存在并已运行。不启动报错。  

2.7.2 请求重试retries

   远程服务调用重试次数,不包括第一次调用,默认是2 次。  加上第一次共3 次。  

<dubbo:reference retries=”5”>

                        第3章   注册中心  

3.1 注册中心Zookeeper

3.1.1 为什么使用注册中心

对于服务提供方,它需要发布服务,而且由于应用系统的复杂性,服务的数量、类型也 

不断膨胀;对于服务消费方,它最关心如何获取到它所需要的服务,而面对复杂的应用系统,
需要管理大量的服务调用。
而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,即需要提供
服务,有需要消费服务。 通过将服务统一管理起来,可以有效地优化内部应用对服务发布/
使用的流程和管理。服务注册中心可以通过特定协议来完成服务对外的统一。Dubbo 提供
的注册中心有如下几种类型可供选:

Multicast 注册中心:组播方式  
Redis 注册中心:使用Redis 作为注册中心  
Simple 注册中心:就是一个dubbo 服务。作为注册中心。提供查找服务的功能。  
Zookeeper 注册中:使用Zookeeper 作为注册中心  
  
推荐使用Zookeeper 注册中心。  
Zookeeper 是Apacahe Hadoop  的子项目,是一个树型的目录服务,支持变更推送,适合 

作为Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。
Zookeeper 就像是windows 的资源管理器,包含了所有的文件。都可以在这里找到。服
务提供者和服务消费者,都在注册中心登记。服务消费者使用的访问地址不用写死。而且注
册中心使用“心跳”机制更新服务提供者的状态。不能使用的服务提供者会自动从注册中心删
除。服务提供者不会调用不能使用的服务。

3.1.2 注册中心是什么?

Zookeeper 是一个高性能的,分布式的,开放源码的分布式应用程序协调服务。简称zk。 

Zookeeper 是翻译管理是动物管理员。可以理解为windows 中的资源管理器或者注册表。他

是一个树形结构。这种树形结构和标准文件系统相似。ZooKeeper 树中的每个节点被称为

Znode。和文件系统的目录树一样,ZooKeeper 树中的每个节点可以拥有子节点。每个节点表

示一个唯一服务资源。Zookeeper 运行需要java 环境。

图一:

3.1.3 注册中心Zookeeper 怎么用

A 、 Zookeeper 下载

官网下载地址: http://zookeeper.apache.org/
进入官网地址,首页找到下载地址,现在稳定版本是3.4.10

选择镜像
点击“Download”

下载3.4.10 版本

B、 Windows 平台Zookeeper 安装,配置

下载的文件zookeeper-3.4.10.tar. 解压后到目录就可以了,例如d:/servers/ zookeeper-3.4.10
修改zookeeper-3.4.10/conf/ 目录下配置文件

复制zoo-sample.cfg 改名为zoo.cfg
文件内容:

tickTime: 心跳的时间,单位毫秒. Zookeeper 服务器之间或客户端与服务器之间维持心跳的
时间间隔,也就是每个 tickTime 时间就会发送一个心跳。表明存活状态。
dataDir: 数据目录,可以是任意目录。存储 zookeeper 的快照文件、pid 文件,默认为
/tmp/zookeeper ,建议在zookeeper 安装目录下创建data 目录,将dataDir 配置改
为/usr/local/zookeeper-3.4.10/data
clientPort: 客户端连接zookeeper 的端口,即zookeeper 对外的服务端口,默认为2181

C、 Linux 平台 Zookeeper 安装、配置

Zookeeper 的运行需要jdk 。使用前Linux 系统要安装好jdk.

①:上传zookeeper-3.4.10.tar.gz 并解压
解压文件zookeeper-3.4.10.tar.gz
执行命令:tar -zxvf zookeeper-3.4.10.tar.gz -C /usr/local/

查看已解压:

②:配置文件
在zookeeper 的conf 目录下,将zoo_sample.cfg 改名为zoo.cfg,cp zoo_sample.cfg zoo.cfg
zookeeper 启动时会读取该文件作为默认配置文件。

进入zookeeper 目录下的conf

拷贝样例文件 zoo-sample.cfg 为 zoo.cfg

③:启动Zookeeper
启动(切换到安装目录的bin 目录下):./zkServer.sh start

④:关闭Zookeeper
关闭(切换到安装目录的bin 目录下):./zkServer.sh stop

D、 Zookeeper 的客户端图形工具

Zookeeper 图形界面的客户端:ZooInspector.
使用方式:Windows 上解压ZooInspector 文件
主界面:

配置连接:

连接成功:
3.2 使用Zookeeper 注册中心

3.2.1 服务提供者:

A 、 拷贝05-ProviderInterfaceImpl 项目,命名为06-ProviderInterfaceImplZk

B、 导入Zookeeper 相关jar

在原来的jar 基础上加入

C、 修改spring 配置文件

修改dubbo-provider.xml

  1. 加入注册中心<dubbo:registry address=“zookeeper://localhost:2181” />
  2. 去掉dubbo:service 中的protocol=“dubbo” registry=“N/A”

修改后文件内容:

3.2.2 服务消费者

A 、 拷贝05-ConsumeService 项目,重新命名为06-ConsumeServiceZk

B、 导入Zookeeper 相关jar

C、 修改spring 配置文件

修改dubbo-consume.xml

  1. 加入注册中心:<dubbo:registry address=“zookeeper://localhost:2181” />
  2. 去掉dubbo:reference 中 url=“dubbo://127.0.0.1:20880”

修改后配置如下:

3.2.3 运行程序

  先运行 Zookeeper           注册中心,再启动服务提供者,最后运行服务消费者。一定要运行 

Zookeeper。因为服务提供者要向Zookeepr 注册服务。服务消费者需要在Zookeeper 查找使
用的服务。

                               第4章   监控中心  

 dubbo   的使用,其实只需要有注册中心,消费者,提供者这三个就可以使用了,但是 

并不能看到有哪些消费者和提供者,为了更好的调试,发现问题,解决问题,因此引入
dubbo-admin 。通过 dubbo-admin 可以对消费者和提供者进行管理。可以在 dubbo 应用部
署做动态的调整,服务的管理。

4.1 发布配置中心

A 、 下载监控中心,https://github.com/alibaba/dubbo

这里下载的是源代码,需要手工编译才能使用。可以在学习maven 后才自己编译。

网络上编译好的,稳定的版本dubbo-admin.war (和rar 类似是一种压缩文件格式)

B、 下载好的dubbo-admin.war 部署到到tomcat 服务器的发布目录

把dubbo-admin.war 文件拷贝到tomcat 的webapps

C、 修改配置dubbo-properties 文件

dubbo-admin 应用的WEB-INF/dubbo-properties 文件,内容如下:

D、 运行dubbo-admin 应用

1) 先启动注册中心
2 ) 发布dubbo 服务提供者和消费者到tomcat ,或者独立jar 运行。
3 ) 启动tomcat,运行控制台web 应用程序。
4 ) 在浏览器地址栏输入 http://localhost:8080/dubbo-admin 。访问监控中心-控制台。

4.2 发布dubbo 项目

(1) 发布web 项目06-ProviderInterfaceImplZk 到tomcat

(2) 服务消费项目改造

A 、 拷贝06-ConsumeServiceZk,改为07-ConsumeServiceZkAdmin

B、 修改main 方法代码

C、 新建InvokeService 类

D、 修改dubbo-consume.xml, 注册InvokeService

(3) 运行dubbo 项目

先启动zookeeper, 再启动tomcat, 浏览器输入http://localhost:8080/dubbo-admin/
首页:

服务治理—服务:

注意:在eclipse 中启动tomcat ,有可能会有超时的情况。双击tomcat 进行配置选项,修改
启动时间。增加启动超时的时间。

                     第5章    负载均衡  

集群:集群是一种计算机系统,是一种服务器结构。把一组多个计算机,包括硬件和软 

件组织在一个网络中。相互连接起来共同完成某个工作。对用户来说使用的是一个计算机,
集群对用户是透明的。
负载均衡:负载均衡是以集群为前提的。英文名称为Load Balance,其意思就是将负载
(工作任务)进行平衡、分摊到多个操作单元上进行执行。
对于网络应用而言,并不是一开始就需要负载均衡,当网络应用的访问量不断增长,单
个处理单元无法满足负载需求时,网络应用流量将要出现瓶颈时,负载均衡才会起到作用。
一般通过一个或者多个前端负载均衡器,将工作负载分发到后端的一组服务器上,从而达到
整个系统的高性能和高可用性。
负载均衡有两方面的含义:首先,单个重负载的工作分配到多台服务器做并行处理,每
个服务器处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高,这是集群
(cluster )技术带来的优势。第二层含义是:大量的并发访问或数据流量分担到多台服务器
分别处理,减少用户等待响应的时间。每个访问分配给不同的服务器处理。

5.1 Dubbo 负载均衡

5.1.1 负载策略

Dubbo 提供了多种均衡策略,缺省为 random 随机调用。

A 、 Random LoadBalance

随机,按权重设置随机概率。  
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较 

均匀,有利于动态调整提供者权重。

B、 RoundRobin LoadBalance

轮循,按公约后的权重设置轮循比率。  
存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时 

就卡在那,久而久之,所有请求都卡在调到第二台上。

C、 LeastActive LoadBalance

最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。  
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。  
D、 ConsistentHash LoadBalance  

  一致性Hash,相同参数的请求总是发到同一提供者。  
  当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者, 

不会引起剧烈变动。算法参见:http://en.wikipedia.org/wiki/Consistent_hashing。
缺省只对第一个参数Hash,如果要修改,请配置<dubbo:parameter key=“hash.arguments”
value=“0,1” />

5.1.2 配置方式:

<dubbo:service interface="…" loadbalance=“roundrobin” />

<dubbo:reference interface="…" loadbalance=“roundrobin” />

随机:loadbalance=” random”
轮询:loadbalance=” roundrobin”
最少活跃:loadbalance=” leastactive”
一致性Hash:loadbalance=” consistenthash”

5.2 代码实现

A 、 06-ProviderInterfaceImplZk 项目,添加输出语句

B、 导出项目,打包war 文件

先用鼠标选中项目,再选择Eclipse 的File 菜单下面的Export

下一步,填写保存的文件名

最后点击Finish

C、 06-ProviderInterfaceImplZk 项目,修改输出语句

D、 导出项目同B 步骤

导出的war 文件名06-ProviderInterfaceImplZkWindows.war
导出后的两个war 文件:

E、 修改06-ConsumeServiceZk 的配置文件dubbo-consume.xml

F、 发布服务提供者项目到tomcat

06-ProviderInterfaceImplZkWindows.war 发布到windows 的tomcat
06-ProviderInterfaceImplZkLinux.war 发布到linux 的tomcat

G、 执行程序

先启动zookeeper, 再启动tomcat , 执行消费者06-ConsumeServiceZk 的测试类。
多执行几次查看输出结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值