├── .gitignore ├── Buffers.md ├── Buffers └── README.md ├── Event Bus ├── Event Bus理论.md ├── README.md ├── 事件总线 API.md ├── 事件总线(Event Bus).md ├── 发布消息.md ├── 发送失败.md ├── 发送消息(EventBus).md ├── 发送超时.md ├── 命令行上的集群.md ├── 消息对象.md ├── 消息编解码器.md ├── 消息设置headers.md ├── 消息顺序.md ├── 确认消息 │ └── 发送答复.md ├── 群集Event Bus.md ├── 自动清理 Verticles .md └── 集群编程.md ├── HTTP ├── README.md ├── 编写 HTTP 客户端.md └── 编写 HTTP 服务器.md ├── JSON └── json.md ├── README.md ├── Reactor和多Reactor.md ├── SUMMARY.md ├── TCP 服务器和客户端.md ├── TCP ├── README.md ├── TCP 客户端.md └── TCP 服务器.md ├── book.json ├── cover.jpg ├── layouts ├── footer.html └── header.html ├── styles ├── ebook.css ├── mobi.css ├── pdf.css └── website.css ├── verticles ├── Context对象.md ├── Vert_x 退出.md ├── Verticles 自动清理.md ├── Verticle类型.md ├── Verticle隔离组.md ├── verticles.md ├── verticle名称映射到一个verticle工厂的规则.md ├── 从命令行运行 Verticles.md ├── 以编程方式部署 verticles.md ├── 取消 verticle 部署.md ├── 在Verticle里访问环境变量.md ├── 异步Verticle启动和停止.md ├── 怎么样找到Verticle Factories.md ├── 执行定期和延迟的操作.md ├── 指定verticle实例数.md ├── 等待部署完成.md ├── 编写Verticles.md ├── 配置verticle.md └── 高可用性(High Availability).md ├── 不要call(调用、打电话)我们,我们会call给你。.md ├── 不要阻塞我.md ├── 从Vert-x开始.md ├── 你是傻瓜吗.md ├── 编写 HTTP 服务器和客户端.md ├── 运行阻塞代码.md └── 黄金法则_不要阻塞事件循环.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /Buffers.md: -------------------------------------------------------------------------------- 1 | # 缓冲区 2 | 3 | 4 | 大多数数据是使用缓冲区抛入Vert.x内。 5 | 6 | 缓冲区是零个或多个字节,可以读取或写入,并自动扩展,以适应任何字节写入它。你或许可以认为缓冲区是智能字节数组。 7 | 8 | #### 创建缓冲区 9 | 10 | 缓冲区可以通过静态的[Buffer.buffer](http://vertx.io/docs/apidocs/io/vertx/core/buffer/Buffer.html#buffer--)方法创建。 11 | 12 | 可以从字符串或字节数组,初始化缓冲区,也可以创建空缓冲区。 13 | 14 | 下面是创建缓冲区的一些示例: 15 | 16 | 创建一个新的空缓冲区: 17 | 18 | ``` 19 | Buffer buff = Buffer.buffer(); 20 | ``` 21 | 22 | 从一个字符串创建一个缓冲区。字符串将在缓冲区中使用 utf-8 编码。 23 | 24 | ``` 25 | Buffer buff = Buffer.buffer("some string"); 26 | ``` 27 | 28 | 从字符串创建缓冲区:该字符串将使用指定的编码,例如: 29 | 30 | ``` 31 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 32 | ``` 33 | 34 | 从 byte[]创建一个缓冲区。 35 | 36 | ``` 37 | byte[] bytes = new byte[] {1, 3, 5}; 38 | Buffer buff = Buffer.buffer(bytes); 39 | ``` 40 | 41 | 创建一个初始大小的缓冲区。如果你知道你的缓冲区将有一定数量的数据写入,你可以在创建缓冲区时指定缓冲区大小。这使得缓冲最初分配多的内存,比缓冲区自动调整多次作为数据写入它更有效。 42 | 43 | 请注意,这种方法创建的缓冲区是空的。它不能创建大小为零的缓冲。 44 | 45 | ``` 46 | Buffer buff = Buffer.buffer(10000); 47 | ``` 48 | 49 | #### 写入缓冲区 50 | 51 | 有两种方法来写入缓冲区:添加、和随机存取。在任何情况下,缓冲区将自动扩展,以包括字节。用缓冲区获取IndexOutOfBoundsException这是不可能的。 52 | 53 | ##### 添加到缓冲区 54 | 55 | 要添加到缓冲区,您可以使用appendXXX方法。添加各种不同类型存在的方法。 56 | 57 | appendXXX方法的返回值是缓冲区本身,以便这些可以将链接: 58 | 59 | ``` 60 | Buffer buff = Buffer.buffer(); 61 | 62 | buff.appendInt(123).appendString("hello\n"); 63 | 64 | socket.write(buff); 65 | ``` 66 | 67 | ##### 写入随机存取缓冲区 68 | 69 | 使用setXXX方法,在特定的索引中,可以写入缓冲区中。Set 的方法存在各种不同的数据类型。所有的设置的方法取索引作为第一个参数-这代表缓冲区中的位置从哪里开始写入数据。 70 | 71 | 缓冲区将总是需要时扩展,以容纳数据。 72 | 73 | ``` 74 | Buffer buff = Buffer.buffer(); 75 | 76 | buff.setInt(1000, 123); 77 | buff.setString(0, "hello"); 78 | ``` 79 | 80 | #### 从缓冲区读取 81 | 82 | 使用getXXX方法从缓冲区读取数据。获得方法存在不同的数据类型。这些方法的第一个参数是获取数据的缓冲区中的一个索引。 83 | 84 | ``` 85 | Buffer buff = Buffer.buffer(); 86 | for (int i = 0; i < buff.length(); i += 4) { 87 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 88 | } 89 | ``` 90 | 91 | #### 使用无符号数字 92 | 93 | 无符号的数字可以通过getUnsignedXXX、 appendUnsignedXXX和setUnsignedXXX的方法读取或追加/套到缓冲区。这是有用的,当实现一个编解码器的网络协议优化,以尽量减少带宽消耗。 94 | 95 | 在以下示例中, 200 是设置在指定的位置只有一个字节: 96 | 97 | ``` 98 | Buffer buff = Buffer.buffer(128); 99 | int pos = 15; 100 | buff.setUnsignedByte(pos, (short) 200); 101 | System.out.println(buff.getUnsignedByte(pos)); 102 | ``` 103 | 104 | 控制台显示 '200'。 105 | 106 | #### 缓冲区长度 107 | 108 | 使用[length](http://vertx.io/docs/apidocs/io/vertx/core/buffer/Buffer.html#length--)来获取缓冲区的长度。缓冲区的长度是在缓冲区的最大索引 + 1 字节的索引。 109 | 110 | #### 复制缓冲区 111 | 112 | 使用[copy](http://vertx.io/docs/apidocs/io/vertx/core/buffer/Buffer.html#copy--),复制缓冲区 113 | 114 | #### 切片的缓冲区 115 | 116 | 切片的缓冲区是一个新的缓冲区,背对着原来的缓冲区,即它将不复制的基础数据。使用[slice](http://vertx.io/docs/apidocs/io/vertx/core/buffer/Buffer.html#slice--)创建切片的缓冲区 117 | 118 | #### 缓冲区重新使用 119 | 120 | 一个缓冲区写入套接字或其它类似的地方之后,他们不能被重新使用。 121 | -------------------------------------------------------------------------------- /Buffers/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quanke/vert-x-core-manual-for-java/56702e9ff519c1d625d445e6bebd888e0c027be1/Buffers/README.md -------------------------------------------------------------------------------- /Event Bus/Event Bus理论.md: -------------------------------------------------------------------------------- 1 | # 理论 2 | 3 | ##### 处理 4 | 5 | 事件到地址总线上发送邮件. 6 | 7 | Vert.x 并不费心处理计划任何幻想。在 Vert.x 的地址是只是一个字符串。任何字符串是有效的。然而它是计划的明智地使用某种类型,例如使用句点划定一个命名空间。 8 | 9 | 一些例子的有效地址是 europe.news.feed1、 acme.games.pacman、 香肠和 X。 10 | 11 | ##### 处理程序 12 | 13 | 在处理程序接收消息。你注册一个处理程序的地址。 14 | 15 | 很多不同的处理程序可以注册在相同的地址。 16 | 17 | 单个处理程序可以注册在许多不同的地址。 18 | 19 | ##### 发布/订阅消息传递 20 | 21 | 事件总线支持发布消息。 22 | 23 | 消息发布到的地址。发布是指信息传递给所有处理程序,注册在该地址。 24 | 25 | 这是熟悉的发布订阅消息传递模式。 26 | 27 | ##### 点到点和请求-响应消息 28 | 29 | 事件总线还支持点到点消息传递。 30 | 31 | 邮件发送到某个地址。Vert.x 然后将传送到位于该地址注册的处理程序之一。 32 | 33 | 如果有多个处理程序,登记的地址,将选择一个使用非严格-轮转调度算法。 34 | 35 | 使用点到点消息传递,发送消息时,可以指定一个可选的答复处理程序。 36 | 37 | 当消息由收件人收到,并且已被处理时,收件人可以选择决定对消息进行回复。如果他们这样做答复处理程序将被调用。 38 | 39 | 当回到在发件人收到的答复时,它也可以被回复。这可以是重复的广告-无穷尽,并允许一个对话框,可以设置两个不同的 verticles 之间。 40 | 41 | 这是一种常见的消息传递模式,称为请求-响应模式。 42 | 43 | ##### 尽最大努力交付 44 | 45 | Vert.x 最好来传递邮件,并不会有意识地把它们扔掉。这就被所谓尽最大努力交付。 46 | 47 | 然而,万一失败的全部或部分的事件总线,有可能性消息将丢失。 48 | 49 | 如果您的应用程序关心丢失的邮件,你应该代码您的处理程序是等幂的和你发件人可以在恢复后重试。 50 | 51 | ##### 类型的消息 52 | 53 | 开箱即用 Vert.x 允许任何原始/简单类型、 字符串或buffers将作为邮件发送。 54 | 55 | 然而它是公约和惯例在 Vert.x 以json 格式发送邮件 56 | 57 | JSON 是很容易创建、 读取和解析在 Vert.x 支持,因此它已成为一种通用语言为 Vert.x 的所有语言。 58 | 59 | 然而你不被迫使用 JSON,如果你不想去。 60 | 61 | 事件总线是非常灵活,也支持通过事件总线发送任意对象。你这样做是通过定义您想要发送的对象的codec。 -------------------------------------------------------------------------------- /Event Bus/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quanke/vert-x-core-manual-for-java/56702e9ff519c1d625d445e6bebd888e0c027be1/Event Bus/README.md -------------------------------------------------------------------------------- /Event Bus/事件总线 API.md: -------------------------------------------------------------------------------- 1 | # 事件总线 API 2 | 3 | 让我们跳进 API 4 | 5 | ##### 获取事件总线 6 | 7 | 你获取到事件总线的引用,如下所示: 8 | 9 | ``` 10 | EventBus eb = vertx.eventBus(); 11 | ``` 12 | 13 | 还有每个 Vert.x 实例事件总线的单个实例。 14 | 15 | ##### 注册处理程序 16 | 17 | 这个最简单的方法来注册一个处理程序用consumer。下面是一个示例: 18 | 19 | ``` 20 | EventBus eb = vertx.eventBus(); 21 | 22 | eb.consumer("news.uk.sport", message -> { 23 | System.out.println("I have received a message: " + message.body()); 24 | }); 25 | ``` 26 | 27 | 当邮件到达您的处理程序时,将调用您的处理程序,在message中传递. 28 | 29 | 从对 consumer() 的调用返回的对象是一个实例MessageConsumer 30 | 随后,此对象可以用于注销处理程序中,或使用处理程序以流的形式。 31 | 32 | 或者你可以使用consumer对返回 MessageConsumer 与没有处理程序设置,然后在那设置处理程序。例如: 33 | 34 | ``` 35 | EventBus eb = vertx.eventBus(); 36 | 37 | MessageConsumer consumer = eb.consumer("news.uk.sport"); 38 | consumer.handler(message -> { 39 | System.out.println("I have received a message: " + message.body()); 40 | }); 41 | ``` 42 | 43 | 注册时聚集的事件总线上的一个处理程序,它可以有一些时间为要达到该群集的所有节点的登记。 44 | 45 | 如果你想要这已完成时通知,您可以注册的 MessageConsumer 对象上completion handler。 46 | 47 | ``` 48 | consumer.completionHandler(res -> { 49 | if (res.succeeded()) { 50 | System.out.println("The handler registration has reached all nodes"); 51 | } else { 52 | System.out.println("Registration failed!"); 53 | } 54 | }); 55 | ``` 56 | 57 | ##### 未注册的处理程序 58 | 59 | 若要撤消注册的处理程序,调用unregister. 60 | 61 | 如果你在一个群集事件总线,未登记可能需要一些时间来传播跨节点,如果你想要这完成后通知使用unregister. 62 | 63 | ``` 64 | consumer.unregister(res -> { 65 | if (res.succeeded()) { 66 | System.out.println("The handler un-registration has reached all nodes"); 67 | } else { 68 | System.out.println("Un-registration failed!"); 69 | } 70 | }); 71 | ``` 72 | -------------------------------------------------------------------------------- /Event Bus/事件总线(Event Bus).md: -------------------------------------------------------------------------------- 1 | # 事件总线(Event Bus) 2 | 3 | [event bus](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/EventBus.html)是Vert.x 的中枢神经系统 。 4 | 5 | 通过Vert.x实例使用eventBus方法得到单一的event bus实例。 6 | 事件总线允许您的应用程序相互沟通,不论何种语言,他们写的以及他们是否在同一个 Vert.x 实例,或在一个不同的 Vert.x 实例的不同部分。 7 | 8 | 它甚至可以弥合,允许客户端 JavaScript 运行在浏览器上相同的事件总线进行通信。 9 | 10 | 事件总线构成了一个分布式对等消息传递系统跨越多个服务器节点和多个浏览器。 11 | 12 | 事件总线支持发布/订阅,点到点和请求-响应消息。 13 | 14 | 事件总线 API 是非常简单的。它基本上涉及注册处理程序,注销处理程序和发送和发布消息。 15 | 16 | 第一次一些理论: -------------------------------------------------------------------------------- /Event Bus/发布消息.md: -------------------------------------------------------------------------------- 1 | # 发布消息 2 | 3 | 发布一条消息是简单的。只需使用publish指定地址发布到。 4 | 5 | ``` 6 | eventBus.publish("news.uk.sport", "Yay! Someone kicked a ball"); 7 | ``` 8 | 9 | 那消息然后将送交注册的反对地址 news.uk.sport 的所有处理程序。 -------------------------------------------------------------------------------- /Event Bus/发送失败.md: -------------------------------------------------------------------------------- 1 | # 发送失败 2 | 3 | 消息发送失败有其他原因,包括: 4 | 5 | * 没有可用来向其发送消息的handlers 6 | * 收件人已明确地使用[fail](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/Message.html#fail-int-java.lang.String-)(失败)的消息 7 | 8 | 在所有情况下回复处理程序将调用具体的失败。 -------------------------------------------------------------------------------- /Event Bus/发送消息(EventBus).md: -------------------------------------------------------------------------------- 1 | # 发送消息 2 | 3 | 发送一条消息将导致只有一个Handlers在接收该消息的地址注册。这是点对点的消息传递模式。这个Handlers的选择是一个非严格的循环方式。 4 | 5 | 发送一条消息时,可以[send](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/EventBus.html#send-java.lang.String-java.lang.Object-) 6 | 7 | ``` 8 | eventBus.send("news.uk.sport", "Yay! Someone kicked a ball"); 9 | ``` -------------------------------------------------------------------------------- /Event Bus/发送超时.md: -------------------------------------------------------------------------------- 1 | # 发送超时 2 | 3 | 发送答复处理消息时你可以在[DeliveryOptions](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/DeliveryOptions.html)中指定超时. 4 | 5 | 如果在该时间内没有收到答复,答复处理程序将调用失败。 6 | 7 | 默认的超时时间为 30 秒。 -------------------------------------------------------------------------------- /Event Bus/命令行上的集群.md: -------------------------------------------------------------------------------- 1 | # 命令行上的集群 2 | 3 | 可以在命令行中运行 Vert.x 集群 4 | 5 | `vertx run my-verticle.js -cluster` -------------------------------------------------------------------------------- /Event Bus/消息对象.md: -------------------------------------------------------------------------------- 1 | # 消息对象 2 | 3 | 4 | 在消息Handlers中接收的对象是一个[Message](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/Message.html)。 5 | 6 | 该消息的body对应于发送或发布的对象。 7 | 8 | 消息标头有headers。 -------------------------------------------------------------------------------- /Event Bus/消息编解码器.md: -------------------------------------------------------------------------------- 1 | # 消息编解码器 2 | 3 | 4 | 如果你定义并注册了一个[message codec](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/MessageCodec.html),你可以将任何对象发送到event bus 上。 5 | 6 | 消息编解码器有一个名称,您在发送或发布该消息时在[DeliveryOptions](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/DeliveryOptions.html)中指定该名称: 7 | 8 | ``` 9 | eventBus.registerCodec(myCodec); 10 | 11 | DeliveryOptions options = new DeliveryOptions().setCodecName(myCodec.name()); 12 | 13 | eventBus.send("orders", new MyPOJO(), options); 14 | ``` 15 | 16 | 如果你总是希望使用相同的编解码器,用于特定类型,那么你可以注册成为一个默认编码解码器,然后你不需要对每个发送的传递选项中指定编码解码器: 17 | 18 | ``` 19 | eventBus.registerDefaultCodec(MyPOJO.class, myCodec); 20 | 21 | eventBus.send("orders", new MyPOJO()); 22 | ``` 23 | 24 | 注销消息编解码器使用[unregisterCodec](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/EventBus.html#unregisterCodec-java.lang.String-). 25 | 26 | 消息的编码解码器不总是要为相同的类型进行编码和解码。例如,您可以编写允许发送,MyPOJO 类的编解码器,但该消息发送到一个处理程序时它到达作为一个 MyOtherPOJO 类。 -------------------------------------------------------------------------------- /Event Bus/消息设置headers.md: -------------------------------------------------------------------------------- 1 | # 消息设置headers 2 | 3 | 通过event bus发送的消息还可以包含头文件。 4 | 5 | 这可以通过发送或发布时提供[DeliveryOptions](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/DeliveryOptions.html)指定: 6 | 7 | ``` 8 | DeliveryOptions options = new DeliveryOptions(); 9 | options.addHeader("some-header", "some-value"); 10 | eventBus.send("news.uk.sport", "Yay! Someone kicked a ball", options); 11 | ``` -------------------------------------------------------------------------------- /Event Bus/消息顺序.md: -------------------------------------------------------------------------------- 1 | # 消息顺序 2 | 3 | 和发送顺序相同。 -------------------------------------------------------------------------------- /Event Bus/确认消息/发送答复.md: -------------------------------------------------------------------------------- 1 | # 确认消息/发送答复 2 | 3 | 当使用[send](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/EventBus.html#send-java.lang.String-java.lang.Object-) event bus 尝试将消息传递到event bus中注册的[MessageConsumer](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/MessageConsumer.html) 。 4 | 5 | 在某些情况下是有用的,发送者知道什么时候,消费者已经收到了消息和"processing"。 6 | 7 | 要确认该消息已被处理,消费者可以通过调用[reply](http://vertx.io/docs/apidocs/io/vertx/core/eventbus/Message.html#reply-java.lang.Object-)对消息进行回复。 8 | 9 | 当发生这种情况时,它会导致一个回复,发送回发送端和应答处理程序被调用的答复。 10 | 11 | 一个例子可以说明这一点: 12 | 13 | 接收: 14 | 15 | ``` 16 | MessageConsumer consumer = eventBus.consumer("news.uk.sport"); 17 | consumer.handler(message -> { 18 | System.out.println("I have received a message: " + message.body()); 19 | message.reply("how interesting!"); 20 | }); 21 | ``` 22 | 23 | 发送: 24 | 25 | ``` 26 | eventBus.send("news.uk.sport", "Yay! Someone kicked a ball across a patch of grass", ar -> { 27 | if (ar.succeeded()) { 28 | System.out.println("Received reply: " + ar.result().body()); 29 | } 30 | }); 31 | ``` 32 | 33 | 应答可以包含一个消息体,它包含有用的信息。 34 | 35 | "processing"实际上指的是应用程序定义和完全取决于在什么消息上消费者并不是 Vert.x event bus 本身知道或关心的东西。 36 | 37 | 一些例子: 38 | 39 | * 一个简单的消息消费者,它实现了一个服务,它返回的时间是一天中的时间,将确认一个消息,包含时间的答复正文 40 | * 如果消息被成功地保存在存储中,或不正确的话,它将实现一个持久队列的消息,如果消息被成功地保存,可能会对其进行应答。 41 | * 如果消息成功处理,它可以从数据库中删除 42 | 43 | -------------------------------------------------------------------------------- /Event Bus/群集Event Bus.md: -------------------------------------------------------------------------------- 1 | # 群集Event Bus 2 | 3 | Event Bus并不仅仅存在于一个单一的Vert.x实例。通过网络上的不同集群实例Vert.x一起就可以形成一个单一的,分布式的,Event Bus。 -------------------------------------------------------------------------------- /Event Bus/自动清理 Verticles .md: -------------------------------------------------------------------------------- 1 | # 自动清理 Verticles 2 | 3 | 如果你从 verticles里注册event bus处理程序,当verticle取消部署时处理程序将被自动注销。 -------------------------------------------------------------------------------- /Event Bus/集群编程.md: -------------------------------------------------------------------------------- 1 | # 集群编程 2 | 3 | 如果您要以编程方式创建您的 Vert.x 实例,通过将 Vert.x 实例配置获得集群的event bus; 4 | 5 | ``` 6 | VertxOptions options = new VertxOptions(); 7 | Vertx.clusteredVertx(options, res -> { 8 | if (res.succeeded()) { 9 | Vertx vertx = res.result(); 10 | EventBus eventBus = vertx.eventBus(); 11 | System.out.println("We now have a clustered event bus: " + eventBus); 12 | } else { 13 | System.out.println("Failed: " + res.cause()); 14 | } 15 | }); 16 | ``` 17 | 18 | 你还应该确保你已经在你的类路径中实现[ClusterManager](http://vertx.io/docs/apidocs/io/vertx/core/spi/cluster/ClusterManager.html),例如默认*HazelcastClusterManager*。 -------------------------------------------------------------------------------- /HTTP/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quanke/vert-x-core-manual-for-java/56702e9ff519c1d625d445e6bebd888e0c027be1/HTTP/README.md -------------------------------------------------------------------------------- /HTTP/编写 HTTP 客户端.md: -------------------------------------------------------------------------------- 1 | # 编写 HTTP 客户端 2 | 3 | #### 创建 HTTP 客户端 4 | 5 | 使用默认选项创建一个HttpClient实例,如下所示: 6 | 7 | ``` 8 | HttpClient client = vertx.createHttpClient(); 9 | ``` 10 | 11 | 如果您想要在创建时配置客户端的选项,如下所示: 12 | 13 | ``` 14 | HttpClientOptions options = new HttpClientOptions().setKeepAlive(false); 15 | HttpClient client = vertx.createHttpClient(options); 16 | ``` 17 | 18 | 19 | #### 发出请求 20 | 21 | Http 客户端非常灵活,可以用各种方式请求。 22 | 23 | http 客户端经常需要将许多请求发送到相同的主机/端口 。为了避免每次发出请求需要重复配置主机/端口,您可以配置客户端的默认主机/端口: 24 | 25 | ``` 26 | HttpClientOptions options = new HttpClientOptions().setDefaultHost("wibble.com"); 27 | // Can also set default port if you want... 28 | HttpClient client = vertx.createHttpClient(options); 29 | client.getNow("/some-uri", response -> { 30 | System.out.println("Received response with status code " + response.statusCode()); 31 | }); 32 | ``` 33 | 34 | 或者可以指定单个请求的主机/端口。 35 | 36 | ``` 37 | HttpClient client = vertx.createHttpClient(); 38 | 39 | // Specify both port and host name 40 | client.getNow(8080, "myserver.mycompany.com", "/some-uri", response -> { 41 | System.out.println("Received response with status code " + response.statusCode()); 42 | }); 43 | 44 | // This time use the default port 80 but specify the host name 45 | client.getNow("foo.othercompany.com", "/other-uri", response -> { 46 | System.out.println("Received response with status code " + response.statusCode()); 47 | }); 48 | ``` 49 | 50 | ##### 没有请求body简单的请求 51 | 52 | 通常情况下,你会想要与没有请求body的 HTTP 请求。这通常是 HTTP GET,OPTIONS和HEAD请求。 53 | 54 | 这是 Vert.x http 客户端的最简单方法,使用前缀与Now的方法。例如[getNow](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpClient.html#getNow-int-java.lang.String-java.lang.String-io.vertx.core.Handler-)。 55 | 56 | 这些方法创建HTTP请求,并在单个方法调用发送,让你提供一个处理程序,将与HTTP响应时调用它回来。 57 | 58 | ``` 59 | HttpClient client = vertx.createHttpClient(); 60 | 61 | // Send a GET request 62 | client.getNow("/some-uri", response -> { 63 | System.out.println("Received response with status code " + response.statusCode()); 64 | }); 65 | 66 | // Send a GET request 67 | client.headNow("/other-uri", response -> { 68 | System.out.println("Received response with status code " + response.statusCode()); 69 | }); 70 | ``` 71 | 72 | 73 | ##### 编写普通的requests 74 | 75 | 不知道想要发送请求方法,运行时才知道。这个用例我们提供通用请求方法例如[request](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpClient.html#request-io.vertx.core.http.HttpMethod-int-java.lang.String-java.lang.String-),可以在运行时指定 HTTP 方法: 76 | 77 | ``` 78 | HttpClient client = vertx.createHttpClient(); 79 | 80 | client.request(HttpMethod.GET, "some-uri", response -> { 81 | System.out.println("Received response with status code " + response.statusCode()); 82 | }).end(); 83 | 84 | client.request(HttpMethod.POST, "foo-uri", response -> { 85 | System.out.println("Received response with status code " + response.statusCode()); 86 | }).end("some-data"); 87 | ``` 88 | 89 | ##### 编写请求主体(bodies) 90 | 91 | 有时想要在requests里含有body,或者想写请求的headers。 92 | 93 | 可以使用[post](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpClient.html#post-int-java.lang.String-java.lang.String-)方法,或者普通的[request](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpClient.html#request-io.vertx.core.http.HttpMethod-int-java.lang.String-java.lang.String-)方法 94 | 95 | 这些方法发送的请求不会立即返回,而是返回[HttpClientRequest](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpClientRequest.html)实例,用于写入body和header。 96 | 97 | 下面是一些写入body和header的 POST 请求的例子: 98 | 99 | ``` 100 | HttpClient client = vertx.createHttpClient(); 101 | 102 | HttpClientRequest request = client.post("some-uri", response -> { 103 | System.out.println("Received response with status code " + response.statusCode()); 104 | }); 105 | 106 | // Now do stuff with the request 107 | request.putHeader("content-length", "1000"); 108 | request.putHeader("content-type", "text/plain"); 109 | request.write(body); 110 | 111 | // Make sure the request is ended when you're done with it 112 | request.end(); 113 | 114 | // Or fluently: 115 | 116 | client.post("some-uri", response -> { 117 | System.out.println("Received response with status code " + response.statusCode()); 118 | }).putHeader("content-length", "1000").putHeader("content-type", "text/plain").write(body).end(); 119 | 120 | // Or event more simply: 121 | 122 | client.post("some-uri", response -> { 123 | System.out.println("Received response with status code " + response.statusCode()); 124 | }).putHeader("content-type", "text/plain").end(body); 125 | ``` 126 | 127 | 默认utf-8编码: 128 | 129 | ``` 130 | request.write("some data"); 131 | 132 | // Write string encoded in specific encoding 133 | request.write("some other data", "UTF-16"); 134 | 135 | // Write a buffer 136 | Buffer buffer = Buffer.buffer(); 137 | buffer.appendInt(123).appendLong(245l); 138 | request.write(buffer); 139 | ``` 140 | 141 | 如果你的 HTTP 请求只写入单个字符串或缓冲区,你可以写它和结束end函数单一调用中的请求。 142 | 143 | ``` 144 | request.end("some simple data"); 145 | 146 | // Write buffer and end the request (send it) in a single call 147 | Buffer buffer = Buffer.buffer().appendDouble(12.34d).appendLong(432l); 148 | request.end(buffer); 149 | ``` 150 | 151 | 当你写到一个请求时,write第一次调用会导致写入网络的请求标头。 152 | 153 | 实际的写操作是异步的之前一段时间后调用已返回, 不是可能发生。 154 | 155 | 非分块请求正文与 HTTP 请求需要要提供的Content-Length标头。 156 | 157 | 因此,如果您不使用分块的 HTTP 然后之前,必须设置Content-Length标头写入请求,否则它将太迟了。 158 | 159 | 如果您正在调用接受字符串或缓冲区的end方法之一然后 Vert.x 将自动计算并设置Content-Length标头在写请求正文之前。 160 | 161 | 如果您使用的 HTTP 分块Content-Length标头不是必需的所以你不需要计算的前期的大小。 -------------------------------------------------------------------------------- /HTTP/编写 HTTP 服务器.md: -------------------------------------------------------------------------------- 1 | # 编写 HTTP 服务器 2 | 3 | #### 创建一个 HTTP 服务器 4 | 5 | 最简单的方法来创建一个 HTTP 服务器,所有选项使用默认的。如下所示: 6 | 7 | ``` 8 | HttpServer server = vertx.createHttpServer(); 9 | ``` 10 | 11 | #### 配置 HTTP 服务器 12 | 13 | 如果你不想使用默认值,创建服务器时可以通过传入一个[HttpServerOptions](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerOptions.html)实例配置: 14 | 15 | ``` 16 | HttpServerOptions options = new HttpServerOptions().setMaxWebsocketFrameSize(1000000); 17 | 18 | HttpServer server = vertx.createHttpServer(options); 19 | ``` 20 | 21 | #### 启动服务器监听 22 | 23 | 使用[listen](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServer.html#listen--)告诉服务器以监听传入的请求。 24 | 25 | 在选项中指定的主机和端口: 26 | 27 | ``` 28 | HttpServer server = vertx.createHttpServer(); 29 | server.listen(); 30 | ``` 31 | 32 | 或在调用listen中指定的主机和端口,忽略配置选项: 33 | 34 | ``` 35 | HttpServer server = vertx.createHttpServer(); 36 | server.listen(8080, "myhost.com"); 37 | ``` 38 | 39 | 默认主机是`0.0.0.0`, '监听所有可用的地址' ,默认端口是80. 40 | 41 | 实际的绑定是异步的,所以服务器可能不会实际被监听,直到一段时间后,调用返回。 42 | 43 | 如果想要listen实际监听后通知你,可以提供listen调用处理程序。例如: 44 | 45 | ``` 46 | HttpServer server = vertx.createHttpServer(); 47 | server.listen(8080, "myhost.com", res -> { 48 | if (res.succeeded()) { 49 | System.out.println("Server is now listening!"); 50 | } else { 51 | System.out.println("Failed to bind!"); 52 | } 53 | }); 54 | ``` 55 | 56 | #### 收到传入请求通知 57 | 58 | 若要请求到达时通知,需要设置[requestHandler](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServer.html#requestHandler-io.vertx.core.Handler-): 59 | 60 | ``` 61 | HttpServer server = vertx.createHttpServer(); 62 | server.requestHandler(request -> { 63 | // Handle the request in here 64 | }); 65 | ``` 66 | 67 | #### 处理请求 68 | 69 | 当请求到达时,则该请求调用处理程序传递[HttpServerRequest](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html)的一个实例。此对象所表示的服务器端的 HTTP 请求。 70 | 71 | 当请求headers已完全读取时,将调用该处理程序。 72 | 73 | 如果该请求包含一个body,该body将到达服务器,一段时间后请求处理程序被调用。 74 | 75 | 服务器请求对象可以获取[uri](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#uri--)、[path](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#path--)、 [params](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#params--)和[headers](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#headers--)等。 76 | 77 | 每个服务器请求对象是与一台服务器的响应对象相关联。使用[response](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#response--)来获取对[HttpServerResponse](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html)对象。 78 | 79 | 这里是一个简单的例子,服务器处理请求和回复"hello world"。 80 | 81 | ``` 82 | vertx.createHttpServer().requestHandler(request -> { 83 | request.response().end("Hello world"); 84 | }).listen(8080); 85 | ``` 86 | 87 | ##### 请求的版本 88 | 89 | HTTP 请求中指定的版本,可以用[version](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#version--)获取 90 | 91 | ##### 请求方法 92 | 93 | [method](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#method--)用于获得请求的 `HTTP` 方法 。(即是GET,POST、 PUT、 DELETE、 HEAD、OPTIONS等)。 94 | 95 | ##### 请求的 URI 96 | 97 | 使用[uri](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#uri--)来获取请求的 URI。 98 | 99 | 注意,这是通过在 HTTP 请求中,实际 URI,它几乎总是相对 URI。 100 | 101 | URI是在 [HTTP规范的5.1.2节中定义 - 请求URI](http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) 102 | 103 | ##### 请求路径 104 | 105 | 使用[path](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#path--)返回 URI 的路径 106 | 107 | 例如,如果请求 URI 只是: 108 | 109 | `a/b/c/page.html?param1=abc¶m2=xyz` 110 | 111 | 那么,路径会 112 | 113 | `/a/b/c/page.html` 114 | 115 | ##### 请求查询 116 | 117 | 使用[query](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#query--)返回的 URI 的查询部分 118 | 119 | 例如,如果请求 URI 只是: 120 | 121 | `a/b/c/page.html?param1=abc¶m2=xyz` 122 | 123 | 那么,该查询会 124 | 125 | `param1=abc¶m2=xyz` 126 | 127 | ##### 请求headers 128 | 129 | 使用[headers](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#headers--)方法来返回的 HTTP 请求headers。 130 | 131 | 这将返回一个实例[MultiMap](http://vertx.io/docs/apidocs/io/vertx/core/MultiMap.html)-就像一个普通的map或Hash,但允许多个值的同一键-这是因为 HTTP 允许多个header值用相同的密钥。 132 | 133 | `key` 不区分大小写,这就意味着您可以执行以下操作: 134 | 135 | ``` 136 | MultiMap headers = request.headers(); 137 | 138 | // Get the User-Agent: 139 | System.out.println("User agent is " + headers.get("user-agent")); 140 | 141 | // You can also do this and get the same result: 142 | System.out.println("User agent is " + headers.get("User-Agent")); 143 | ``` 144 | 145 | ##### 请求参数 146 | 147 | 使用[params](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#params--)返回的 HTTP 请求参数。 148 | 149 | 就像[headers](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#headers--)这返回的[MultiMap](http://vertx.io/docs/apidocs/io/vertx/core/MultiMap.html)实例,可以有多个参数具有相同的名称。 150 | 151 | 路径后的请求 URI是请求参数。例如,如果 URI: 152 | 153 | ``` 154 | /page.html?param1=abc¶m2=xyz 155 | ``` 156 | 157 | 然后参数将包含以下内容: 158 | 159 | ``` 160 | param1: 'abc' 161 | param2: 'xyz 162 | ``` 163 | 164 | 请注意这些请求参数从请求的 URL。如果您有已作为体内的multi-part/form-data请求提交 HTML 表单提交的一部分发送的窗体属性然后他们将不出现在这里的 params。 165 | 166 | 请注意,这些请求参数从请求的URL中获取。如果你的form属性为`multi-part/form-data`请求的话,参数不会出现在这里,会包含在body中提交发送。 167 | 168 | 169 | ##### 远程地址 170 | 171 | 请求的发送者的地址可以通过[remoteaddress](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#remoteAddress--)获取。 172 | 173 | ##### 绝对 URI 174 | 175 | 传入的 HTTP 请求的 URI 是通常相对。如果想要检索对应于该请求的绝对 URI,可以用[absoluteURI](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#absoluteURI--) 176 | 177 | ##### 结束处理程序 178 | 179 | 当整个,包括任何body已完全读取请求时,将调用[endHandler](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#endHandler-io.vertx.core.Handler-)请求。 180 | 181 | ##### 从请求正body读取数据 182 | 183 | 通常一个 HTTP 请求包含我们想要读取的body。前面所提到的请求处理程序仅仅有headers,这里并没有body。 184 | 185 | 这是因为body可能会非常大 (例如一个文件上传),我们通常不不会吧缓冲的整个body放在内存中交给你,因为那将导致服务器内存用尽。 186 | 187 | 若要接收body,您可以使用[handler](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#handler-io.vertx.core.Handler-)请求,调用后,会有请求body到达。下面是一个示例: 188 | 189 | ``` 190 | request.handler(buffer -> { 191 | System.out.println("I have received a chunk of the body of length " + buffer.length()); 192 | }); 193 | ``` 194 | 195 | 传递到handler的对象是一个[Buffer](http://vertx.io/docs/apidocs/io/vertx/core/buffer/Buffer.html),该handler可以调用多次,当数据到达时从网络,根据body的大小。 196 | 197 | 在某些情况下 (例如如果body很小) 想要在内存中缓存整个body如下所示: 198 | 199 | ``` 200 | Buffer totalBuffer = Buffer.buffer(); 201 | 202 | request.handler(buffer -> { 203 | System.out.println("I have received a chunk of the body of length " + buffer.length()); 204 | totalBuffer.appendBuffer(buffer); 205 | }); 206 | 207 | request.endHandler(v -> { 208 | System.out.println("Full body received, length = " + totalBuffer.length()); 209 | }); 210 | ``` 211 | 212 | 这是这种常见的情况,Vert.x 提供[bodyHandler](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#bodyHandler-io.vertx.core.Handler-)来为你做这个。bodyHandler收到所有的body: 213 | 214 | ``` 215 | request.bodyHandler(totalBuffer -> { 216 | System.out.println("Full body received, length = " + totalBuffer.length()); 217 | }); 218 | ``` 219 | 220 | ##### Pumping requests 221 | 222 | 请求对象是[ReadStream](http://vertx.io/docs/apidocs/io/vertx/core/streams/ReadStream.html) ,所以你可以pump请求body到任何[WriteStream](http://vertx.io/docs/apidocs/io/vertx/core/streams/WriteStream.html)实例。 223 | 224 | 225 | ##### 处理 HTML 表单 226 | 227 | HTML表单可以提交`application/x-www-form-urlencoded`或`multipart/form-data`内容类型。 228 | 229 | 对于 url 编码形式,像正常的查询参数一样,把表单属性编码在 url 中。 230 | 231 | multi-part表单在请求body中编码,因此不可用直到从wire读取了整个body。 232 | 233 | Multi-part 表单还可以包含文件上传。 234 | 235 | 如果您想要获取的属性是multi-part的形式,得到这种表单之前,通过调用[setExpectMultipart](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#setExpectMultipart-boolean-) 设置为true,告诉 Vert.x 你期望的body是read,,然后你应该使用formAttributes获取 ,读取所有body的属性: 236 | 237 | ``` 238 | server.requestHandler(request -> { 239 | request.setExpectMultipart(true); 240 | request.endHandler(v -> { 241 | // The body has now been fully read, so retrieve the form attributes 242 | MultiMap formAttributes = request.formAttributes(); 243 | }); 244 | }); 245 | ``` 246 | 247 | ##### 处理表单文件上传 248 | 249 | Vert.x 还可以处理在multi-part请求body中编码文件上传。 250 | 251 | 接收文件上传,告诉 Vert.x 期望multi-part表单形式并要求设置[uploadHandler](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#uploadHandler-io.vertx.core.Handler-)。 252 | 253 | 每个上传到服务器上,此handler将调用一次。 254 | 255 | 传递到handler的对象是一个[HttpServerFileUpload](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerFileUpload.html)实例。 256 | 257 | ``` 258 | server.requestHandler(request -> { 259 | request.setExpectMultipart(true); 260 | request.uploadHandler(upload -> { 261 | System.out.println("Got a file upload " + upload.name()); 262 | }); 263 | }); 264 | ``` 265 | 266 | 上传的文件可能会很大,我们不提供单个缓冲区上传整个数据,因为这可能导致内存消耗殆尽,取而代之的是,上传的数据在块中收到: 267 | 268 | ``` 269 | request.uploadHandler(upload -> { 270 | upload.handler(chunk -> { 271 | System.out.println("Received a chunk of the upload of length " + chunk.length()); 272 | }); 273 | }); 274 | ``` 275 | 276 | 上传对象是[ReadStream](http://vertx.io/docs/apidocs/io/vertx/core/streams/ReadStream.html) ,所以你可以pump请求body到任何[WriteStream](http://vertx.io/docs/apidocs/io/vertx/core/streams/WriteStream.html)实例。 277 | 278 | 如果你只是想要上传文件到磁盘,你可以使用[streamToFileSystem](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerFileUpload.html#streamToFileSystem-java.lang.String-): 279 | 280 | ``` 281 | request.uploadHandler(upload -> { 282 | upload.streamToFileSystem("myuploads_directory/" + upload.filename()); 283 | }); 284 | ``` 285 | 286 | > 警告 287 | > 确保您在一个生产系统中检查文件,以避免恶意客户端将文件上传到您的文件系统。查看更多信息的[安全说明](http://vertx.io/docs/vertx-core/java/#_security_notes)。 288 | 289 | 290 | #### 发送返回响应 291 | 292 | 服务器的响应对象是[HttpServerResponse](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html)的实例和所得的请求[response](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html#response--). 293 | 294 | 响应对象用于写回 HTTP 客户端的响应。 295 | 296 | ##### 设置状态代码和消息 297 | 298 | response 的默认 HTTP 状态码是200,表示OK. 299 | 300 | 使用[setStatusCode](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#setStatusCode-int-)来设置不同的代码。 301 | 302 | 您还可以使用[setStatusMessage](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#setStatusMessage-java.lang.String-)指定一个自定义的状态消息. 303 | 304 | 如果您不指定一条状态消息,将使用默认的状态代码。 305 | 306 | ##### 写入 HTTP responses(响应) 307 | 308 | 使用一个[write](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#write-io.vertx.core.buffer.Buffer-)操作,将数据写入 HTTP responses。 309 | 310 | 这些可以在响应结束之前多次调用。可以以下面几种方法调用: 311 | 312 | 用一个缓冲区: 313 | 314 | ``` 315 | HttpServerResponse response = request.response(); 316 | response.write(buffer); 317 | ``` 318 | 319 | 用一个字符串。在这种情况下将默认使用UTF-8编码。 320 | 321 | ``` 322 | HttpServerResponse response = request.response(); 323 | response.write("hello world!"); 324 | ``` 325 | 326 | 使用一个字符串和编码。在本例的字符串将使用指定的编码。 327 | 328 | ``` 329 | HttpServerResponse response = request.response(); 330 | response.write("hello world!", "UTF-16"); 331 | ``` 332 | 333 | 写入responses是异步的,在写入队列后立即返回。 334 | 335 | 如果你只是写一个字符串或缓存HTTP response,你可以写它和调用[end](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#end-java.lang.String-)结束response 336 | 337 | 在响应头第一个调用正在被写入结果的响应 338 | 第一次调用将写入结果正在被写入到响应响应头。因此,如果您不使用 HTTP 分块然后之前,必须设置Content-Length标头写的反应,因为它否则就太晚了。如果您使用的 HTTP 分块你不必担心。 339 | 340 | 第一次调用写结果的响应头被写入响应。因此,如果你不使用HTTP分块,那么header,你必须设置响应的Content-Length。如果您使用HTTP分块你不必担心。 341 | 342 | ##### 结束 HTTP responses 343 | 344 | 一旦你完成了 HTTP responses你应该[end](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#end-java.lang.String-)它。 345 | 346 | 这可以有以下几种方式: 347 | 348 | 不带任何参数,response 是只是结束。 349 | 350 | ``` 351 | HttpServerResponse response = request.response(); 352 | response.write("hello world!"); 353 | response.end(); 354 | ``` 355 | 356 | 它也可以用字符串调用或和缓冲区相同的方式 write。在这种情况下,首先用字符串写入缓冲区,然后和不带参数的一样。例如: 357 | 358 | 359 | ``` 360 | HttpServerResponse response = request.response(); 361 | response.end("hello world!"); 362 | ``` 363 | 364 | 365 | ##### 关闭底层连接 366 | 367 | 368 | 使用 [close](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#close--) 关闭底层的 TCP 连接. 369 | 370 | 短连接在 response 结束时, `Vert.x` 将自动关闭 。 371 | 372 | 长连接的 Vert.x 默认情况下是不会自动的关闭。如果你希望连接保持到空闲时间后关闭,使用 [setIdleTimeout](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerOptions.html#setIdleTimeout-int-) 方法配置。 373 | 374 | ##### 设置 response headers 375 | 376 | 可以将 HTTP response headers 通过 response 直接添加到 [headers](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#headers--): 377 | 378 | ``` 379 | HttpServerResponse response = request.response(); 380 | MultiMap headers = response.headers(); 381 | headers.set("content-type", "text/html"); 382 | headers.set("other-header", "wibble"); 383 | ``` 384 | 385 | 或者你可以使用putHeader 386 | 387 | ``` 388 | HttpServerResponse response = request.response(); 389 | response.putHeader("content-type", "text/html").putHeader("other-header", "wibble"); 390 | ``` 391 | 392 | Headers 必须添加在所有写入response body之前。 393 | 394 | ##### 分块 HTTP 响应和传输 395 | 396 | Vert.x 支持HTTP 分块传输编码. 397 | 398 | 表示输出的内容长度不能确定。 399 | 400 | 把 HTTP response 设置为分块模式,如下所示: 401 | 402 | ``` 403 | HttpServerResponse response = request.response(); 404 | response.setChunked(true); 405 | ``` 406 | 407 | 默认值为非分块。在分块模式下,每次调用 [write](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#write-io.vertx.core.buffer.Buffer-) 调用时,就会写出一个新的 HTTP 块。 408 | 409 | 当在分块模式中你也可以写入 HTTP response 传输到response。实际上,这些实际上写入响应的最后块。 410 | 411 | 若要添加trailers到response,直接添加到trailers. 412 | 413 | ``` 414 | HttpServerResponse response = request.response(); 415 | response.setChunked(true); 416 | MultiMap trailers = response.trailers(); 417 | trailers.set("X-wibble", "woobble").set("X-quux", "flooble"); 418 | ``` 419 | 420 | 或使用putTrailer. 421 | 422 | ``` 423 | HttpServerResponse response = request.response(); 424 | response.setChunked(true); 425 | response.putTrailer("X-wibble", "woobble").putTrailer("X-quux", "flooble"); 426 | ``` 427 | 428 | ##### 直接从磁盘或类路径(classpath)提供文件服务 429 | 430 | 如果你正在编写一个Web服务器,使用AsyncFile打开磁盘上的文件并注入到HTTP response。 431 | 432 | 或者你可以一气呵成,使用[readFile](http://vertx.io/docs/apidocs/io/vertx/core/file/FileSystem.html#readFile-java.lang.String-io.vertx.core.Handler-)加载并直接写入响应。 433 | 434 | 另外,Vert.x 提供了一种方法,可以从磁盘或者文件系统操作HTTP response。由底层操作系统支持,这可能在OS中直接从文件到套接字传送字节,而无需通过用户空间(user-space)复制。 435 | 436 | 对于大文件使用sendFile,通常更有效,但小文件可能较慢。 437 | 438 | 下面是使用sendFile,提供了一个非常简单的Web服务器: 439 | 440 | ``` 441 | vertx.createHttpServer().requestHandler(request -> { 442 | String file = ""; 443 | if (request.path().equals("/")) { 444 | file = "index.html"; 445 | } else if (!request.path().contains("..")) { 446 | file = request.path(); 447 | } 448 | request.response().sendFile("web/" + file); 449 | }).listen(8080); 450 | ``` 451 | 452 | 发送的文件是异步的,可能无法马上返回。如果你想要该文件写入完成通知,可以使用[sendFile](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerResponse.html#sendFile-java.lang.String-io.vertx.core.Handler-) 453 | 454 | 注意 455 | > 如果你在使用的 HTTPS 使用sendFile会通过用户空间 ,因为如果内核将数据直接从磁盘对套接字,没有机会给应用任何加密。 456 | 457 | 警告 458 | 459 | > 如果你要直接使用 Vert.x 写 web 服务器,小心用户访问其他文件路径,使用 Vert.x Web可能更安全,。 460 | 461 | 当只需要一个文件片段,可以给定从某字节开发,可以通过下面达到: 462 | 463 | ``` 464 | vertx.createHttpServer().requestHandler(request -> { 465 | long offset = 0; 466 | try { 467 | offset = Long.parseLong(request.getParam("start")); 468 | } catch (NumberFormatException e) { 469 | // error handling... 470 | } 471 | 472 | long end = Long.MAX_VALUE; 473 | try { 474 | end = Long.parseLong(request.getParam("end")); 475 | } catch (NumberFormatException e) { 476 | // error handling... 477 | } 478 | 479 | request.response().sendFile("web/mybigfile.txt", offset, end); 480 | }).listen(8080); 481 | ``` 482 | 483 | 如果想要发送的文件从偏移量开始到结束,您不需要提供长度,在这种情况下你可以这么做: 484 | 485 | ``` 486 | vertx.createHttpServer().requestHandler(request -> { 487 | long offset = 0; 488 | try { 489 | offset = Long.parseLong(request.getParam("start")); 490 | } catch (NumberFormatException e) { 491 | // error handling... 492 | } 493 | 494 | request.response().sendFile("web/mybigfile.txt", offset); 495 | }).listen(8080); 496 | ``` 497 | 498 | 499 | ##### 注入responses 500 | 501 | 服务器response是一个[WriteStream](http://vertx.io/docs/apidocs/io/vertx/core/streams/WriteStream.html)实例,可以从任何[ReadStream](http://vertx.io/docs/apidocs/io/vertx/core/streams/ReadStream.html)注入,例如[AsyncFile](http://vertx.io/docs/apidocs/io/vertx/core/file/AsyncFile.html),[NetSocket](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html),[WebSocket](http://vertx.io/docs/apidocs/io/vertx/core/http/WebSocket.html)或[HttpServerRequest](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerRequest.html)。 502 | 503 | 这是一个PUT请求body返回响应的例子,使用pump,即使HTTP请求body比内存大的多,也能正常工作: 504 | 505 | ``` 506 | vertx.createHttpServer().requestHandler(request -> { 507 | HttpServerResponse response = request.response(); 508 | if (request.method() == HttpMethod.PUT) { 509 | response.setChunked(true); 510 | Pump.pump(request, response).start(); 511 | request.endHandler(v -> response.end()); 512 | } else { 513 | response.setStatusCode(400).end(); 514 | } 515 | }).listen(8080); 516 | ``` 517 | 518 | #### HTTP 压缩 519 | 520 | Vert.x 带有 HTTP 压缩开箱即用支持。 521 | 522 | 这意味着在发送回客户端之前能自动压缩响应的主体。 523 | 524 | 如果客户端不支持 HTTP 压缩,将没有压缩 body 响应发送回。 525 | 526 | 这可以同时处理支持 HTTP 压缩的客户端和那些不支持HTTP 压缩的客户端。 527 | 528 | 若要启用压缩,使用[setCompressionSupported](http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerOptions.html#setCompressionSupported-boolean-)配置。 529 | 530 | 默认情况下不启用压缩。 531 | 532 | 当启用 HTTP 压缩,服务器将检查客户端是否包括Accept-Encoding的报头,它包含支持的压缩方式。常用的有deflate和 gzip([Web服务器处理HTTP压缩之gzip、deflate压缩](http://quanke.name/2016/05/01/Web服务器处理HTTP压缩之gzip、deflate压缩/))。 Vert.x 两者都支持。 533 | 534 | 如果服务器将自动压缩与一个支持压缩响应正文中的并将其发送回客户端,就找到这种头。 535 | 如果找到这样的报头,服务器将自动压缩发送回客户端。 536 | 537 | 要知道压缩可能能够减少网络流量,但是是需要消耗更多的 `CPU` 。 -------------------------------------------------------------------------------- /JSON/json.md: -------------------------------------------------------------------------------- 1 | # JSON 2 | 3 | 4 | 不像一些其他语言,Java没有对JSON提供一流的支持,所以我们提供了两个类,来使你的应用程序Vert.x处理JSON更容易一点。 5 | 6 | #### JSON 对象 7 | 8 | [JsonObject](http://vertx.io/docs/apidocs/io/vertx/core/json/JsonObject.html)类表示 JSON 对象。 9 | 10 | JSON对象基本上是有字符串键和值的map,值可以是JSON的一个支持的类型(字符串,数字,布尔值)。 11 | 12 | JSON 对象还支持 null 值。 13 | 14 | ##### 创建 JSON 对象 15 | 16 | 可以使用默认的构造函数创建空的 JSON 对象。 17 | 18 | 可以通过 JSON 格式字符串创建一个 JSON 对象,如下所示: 19 | 20 | ``` 21 | String jsonString = "{\"foo\":\"bar\"}"; 22 | JsonObject object = new JsonObject(jsonString); 23 | ``` 24 | 25 | ##### 条目放入 JSON 对象 26 | 27 | 使用[put](http://vertx.io/docs/apidocs/io/vertx/core/json/JsonObject.html#put-java.lang.String-java.lang.Enum-)方法将值放入的 JSON 对象。 28 | 29 | 该方法可以链接调用,因为使用 fluent API: 30 | 31 | ``` 32 | JsonObject object = new JsonObject(); 33 | object.put("foo", "bar").put("num", 123).put("mybool", true); 34 | ``` 35 | 36 | ##### 从 JSON 对象中获取值 37 | 38 | 使用getXXX方法从 JSON 对象中获取值,例如 : 39 | 40 | ``` 41 | String val = jsonObject.getString("some-key"); 42 | int intVal = jsonObject.getInteger("some-other-key"); 43 | ``` 44 | 45 | #####JSON 对象转换为字符串 46 | 47 | 使用 [encode](http://vertx.io/docs/apidocs/io/vertx/core/json/JsonObject.html#encode--) 对象编码为一个字符串形式。 48 | 49 | #### JSON 数组 50 | [JsonArray](http://vertx.io/docs/apidocs/io/vertx/core/json/JsonArray.html)类表示 JSON 数组。 51 | 52 | 一个 JSON 数组是一个序列的值 (字符串、 数字、 布尔值)。 53 | 54 | JSON 数组也可以包含空值。 55 | 56 | ##### 创建 JSON 数组 57 | 58 | 可以使用默认的构造函数创建空的 JSON 数组。 59 | 60 | 可以通过 JSON 格式字符串创建一个 JSON 数组,如下所示: 61 | ``` 62 | String jsonString = "[\"foo\",\"bar\"]"; 63 | JsonArray array = new JsonArray(jsonString); 64 | ``` 65 | 66 | ##### 添加一个条目到 JSON 数组 67 | 68 | 使用add方法将条目添加到 JSON 数组。 69 | 70 | ``` 71 | JsonArray array = new JsonArray(); 72 | array.add("foo").add(123).add(false); 73 | ``` 74 | 75 | ##### 从 JSON 数组中获取值 76 | 77 | 使用getXXX方法从 JSON 数组中获取值,例如 : 78 | 79 | ``` 80 | String val = array.getString(0); 81 | Integer intVal = array.getInteger(1); 82 | Boolean boolVal = array.getBoolean(2); 83 | ``` 84 | 85 | ##### JSON 数组转换为字符串 86 | 87 | 使用[encode](http://vertx.io/docs/apidocs/io/vertx/core/json/JsonArray.html#encode--)方法将数组编码成字符串形式。 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java API 版本的Vert.x Core 手册 2 | 3 | - 欢迎关注http://quanke.name/ 4 | - 交流群:`231419585` 5 | - 阅读地址:http://vertx.help/ 6 | - 下载地址:https://www.gitbook.com/book/quanke/vert-x-core-manual-for-java 7 | - 本书源码地址:https://github.com/quanke/vert-x-core-manual-for-java 8 | 9 | 本人英语水平有限,有任何问题,请加群交流 :`231419585` 10 | 11 | ------ 12 | 源码在[github](https://github.com/eclipse/vert.x)上 13 | 14 | Vert.x Core提供的功能: 15 | 16 | * 编写TCP客户端和服务器 17 | * 编写 HTTP 客户端和服务器包括 Websocket 支持 18 | * 事件总线(Event bus) 19 | * 共享的数据-本地的map和分布式的map 20 | * 定时和延时运行 21 | * 部署和非部署 Verticles 22 | * Sockets 23 | * DNS 客户端 24 | * 文件系统 25 | * 高可用性 26 | * 集群 27 | 28 | Vert.x核心功能是相当简单的 — — 你不会找到数据库访问、 授权或高级别 web 功能等,这些东西你可以在哪里找到?在这里-,**Vert.x ext**(扩展)。 29 | 30 | Vert.x core 非常小,非常轻量级。只是使用你想要的部分。也是完全可嵌入在您现有的应用程序 — — 不强迫你使用特殊方式架构您的应用程序,这样你可以方向使用 Vert.x。 31 | 32 | 33 | 您可以使用任何 Vert.x 支持的其他语言的核心。这有点小酷-我们不强迫你使用 Java API ,JavaScript 或者 Ruby等都没问题 — — 毕竟,不同的语言有不同的习惯和语法,迫使Ruby 开发人员使用 Java 的语法,这会很奇怪 (举个例子)。相反,我们自动生成以 Java Api 为核心,等效、地道的每种语言。 34 | 35 | 从现在起我们会使用 core 指 Vert.x core。 36 | 37 | 如果你使用 Maven 或 Gradle,需要增加以下依赖才能使用Vert.x Core API: 38 | 39 | * Maven (在你的pom.xml中增加): 40 | 41 | ``` 42 | 43 | io.vertx 44 | vertx-core 45 | 3.2.0 46 | 47 | ``` 48 | 49 | * Gradle (在您的build.gradle文件增加): 50 | 51 | ``` 52 | compile io.vertx:vertx-core:3.2.0 53 | ``` 54 | 55 | 下面让我们来讨论 `core` 的不同概念和功能。 56 | -------------------------------------------------------------------------------- /Reactor和多Reactor.md: -------------------------------------------------------------------------------- 1 | # Reactor和多Reactor 2 | 3 | 之前提到Vert.x API是事件驱动 - 当他们都可用时,Vert.x传递事件给处理程序。 4 | 5 | 在大多数情况下Vertx要求使用一种称为event loop线程的处理程序。 6 | 7 | 如无有 Vert.x 或您的应用程序块中,event loop可以欢快地运行将事件传递给不同的处理程序提供事件陆续到达。 8 | 9 | 因为没有阻塞,event loop可以在短时间内提供大量的事件。例如一个单一的event loop可以非常迅速地处理成千上万的 HTTP 请求。 10 | 11 | 我们把这个叫做反应器模式([Reactor Pattern](http://en.wikipedia.org/wiki/Reactor_pattern)). 12 | 13 | 你可能会有之前听说过-例如 Node.js 实现此模式。 14 | 15 | 标准的Reactor所有事件都运行在单一事件循环线程。 16 | 17 | 单个线程的麻烦是在任何一个时间它只能运行在单一的核心上(例如 Node.js 应用,如果想要实现多线程你要做很多事 。 18 | 19 | 而Vert.x 不同。不是单事件循环,每个 Vertx 实例都维护若干个事件循环。默认情况下,我们选择数量基于在机器上可用的内核数,但可以自己设置。 20 | 21 | 与 Node.js 不同是Vertx进程是可配置的,与 Node.js 不同 22 | 23 | 我们称这种模式多反应器(Multi-Reactor)模式,以区别于单线程的反应器模式。 24 | 25 | *注意:即使 Vertx 实例维护多个事件循环,任何特定的处理程序将永远不会被同时执行,在大多数情况下 (除了 [worker verticles](http://vertx.io/docs/vertx-core/java/#worker_verticles)) 将始终使用完全相同的事件循环调用。* -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [从Vert.x开始](从Vert-x开始.md) 5 | * [你是傻瓜吗](你是傻瓜吗.md) 6 | * [不要call(调用、打电话)我们,我们会call给你。](不要call(调用、打电话)我们,我们会call给你。.md) 7 | * [不要阻塞我](不要阻塞我.md) 8 | * [Reactor和多Reactor](Reactor和多Reactor.md) 9 | * [黄金法则 — 不要阻塞事件循环](黄金法则_不要阻塞事件循环.md) 10 | * [运行阻塞代码](运行阻塞代码.md) 11 | * [Verticles](verticles/verticles.md) 12 | * [编写 Verticles](verticles/编写Verticles.md) 13 | * [异步Verticle启动和停止](verticles/异步Verticle启动和停止.md) 14 | * [Verticle类型](verticles/Verticle类型.md) 15 | * [以编程方式部署 verticles](verticles/以编程方式部署 verticles.md) 16 | * [verticle名称映射到一个verticle工厂的规则](verticles/verticle名称映射到一个verticle工厂的规则.md) 17 | * [怎么样找到Verticle Factories?](verticles/怎么样找到Verticle Factories.md) 18 | * [等待部署完成](verticles/等待部署完成.md) 19 | * [取消 verticle 部署](verticles/取消 verticle 部署.md) 20 | * [指定verticle实例数](verticles/指定verticle实例数.md) 21 | * [配置verticle](verticles/配置verticle.md) 22 | * [在Verticle里访问环境变量。](verticles/在Verticle里访问环境变量.md) 23 | * [Verticle隔离组](verticles/Verticle隔离组.md) 24 | * [高可用性(High Availability)](verticles/高可用性(High Availability).md) 25 | * [从命令行运行 Verticles](verticles/从命令行运行 Verticles.md) 26 | * [Vert.x 退出](verticles/Vert_x 退出.md) 27 | * [Context对象](verticles/Context对象.md) 28 | * [执行定期和延迟的操作](verticles/执行定期和延迟的操作.md) 29 | * [Verticles 自动清理](verticles/Verticles 自动清理.md) 30 | * [事件总线(Event Bus)](Event Bus/事件总线(Event Bus).md) 31 | * [理论](Event Bus/Event Bus理论.md) 32 | * [事件总线 API](Event Bus/事件总线 API.md) 33 | * [发布消息](Event Bus/发布消息.md) 34 | * [发送消息](Event Bus/发送消息(EventBus).md) 35 | * [消息设置headers](Event Bus/消息设置headers.md) 36 | * [消息顺序](Event Bus/消息顺序.md) 37 | * [消息对象](Event Bus/消息对象.md) 38 | * [确认消息/发送答复](Event Bus/确认消息/发送答复.md) 39 | * [发送超时](Event Bus/发送超时.md) 40 | * [发送失败](Event Bus/发送失败.md) 41 | * [消息编解码器](Event Bus/消息编解码器.md) 42 | * [群集Event Bus](Event Bus/群集Event Bus.md) 43 | * [集群编程](Event Bus/集群编程.md) 44 | * [命令行上的集群](Event Bus/命令行上的集群.md) 45 | * [自动清理 Verticles](Event Bus/自动清理 Verticles .md) 46 | * [JSON](JSON/json.md) 47 | * [Buffers](Buffers.md) 48 | * [编写 TCP 服务器和客户端](TCP 服务器和客户端.md) 49 | * [编写 TCP 服务器](TCP/TCP 服务器.md) 50 | * [编写 TCP 客户端](TCP/TCP 客户端.md) 51 | * [编写 HTTP 服务器和客户端](编写 HTTP 服务器和客户端.md) 52 | * [编写 HTTP 服务器](HTTP/编写 HTTP 服务器.md) 53 | * [编写 HTTP 客户端](HTTP/编写 HTTP 客户端.md) 54 | 55 | -------------------------------------------------------------------------------- /TCP 服务器和客户端.md: -------------------------------------------------------------------------------- 1 | # 编写 TCP 服务器和客户端 2 | 3 | Vert.x 可以轻松地编写非阻塞的 TCP 客户端和服务器。 -------------------------------------------------------------------------------- /TCP/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quanke/vert-x-core-manual-for-java/56702e9ff519c1d625d445e6bebd888e0c027be1/TCP/README.md -------------------------------------------------------------------------------- /TCP/TCP 客户端.md: -------------------------------------------------------------------------------- 1 | # 编写 TCP 客户端 2 | 3 | #### 创建 TCP 客户端 4 | 5 | 最简单的方法来创建一个 TCP 客户端,使用默认选项如下所示: 6 | 7 | ``` 8 | NetClient client = vertx.createNetClient(); 9 | ``` 10 | 11 | #### 配置 TCP 客户端 12 | 13 | 如果你不想使用默认值,则创建TCP 客户端时,通过传入[NetClientOptions](http://vertx.io/docs/apidocs/io/vertx/core/net/NetClientOptions.html)实例可以配置: 14 | 15 | ``` 16 | NetClientOptions options = new NetClientOptions().setConnectTimeout(10000); 17 | NetClient client = vertx.createNetClient(options); 18 | ``` 19 | 20 | #### 建立连接 21 | 22 | 要连接到的服务器可以使用[connect](http://vertx.io/docs/apidocs/io/vertx/core/net/NetClient.html#connect-int-java.lang.String-io.vertx.core.Handler-),指定端口和服务器地址和一个handler,handler包含 [NetSocket](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html) 和成功或者失败的结果。 23 | 24 | ``` 25 | NetClientOptions options = new NetClientOptions().setConnectTimeout(10000); 26 | NetClient client = vertx.createNetClient(options); 27 | client.connect(4321, "localhost", res -> { 28 | if (res.succeeded()) { 29 | System.out.println("Connected!"); 30 | NetSocket socket = res.result(); 31 | } else { 32 | System.out.println("Failed to connect: " + res.cause().getMessage()); 33 | } 34 | }); 35 | ``` 36 | 37 | #### 配置自动重连 38 | 39 | 无法连接可以配置为自动重连。配置[setReconnectInterval](http://vertx.io/docs/apidocs/io/vertx/core/net/NetClientOptions.html#setReconnectInterval-long-)和[setReconnectAttempts](http://vertx.io/docs/apidocs/io/vertx/core/net/NetClientOptions.html#setReconnectAttempts-int-). 40 | 41 | > 注意 42 | 目前 Vert.x 不会尝试重新连接,如果连接失败,重连和重连间隔仅适用于创建初始连接。 43 | 44 | ``` 45 | NetClientOptions options = new NetClientOptions(). 46 | setReconnectAttempts(10).//重连次数 47 | setReconnectInterval(500)//重连间隔 48 | 49 | NetClient client = vertx.createNetClient(options); 50 | ``` 51 | 52 | 默认情况下,自动重连不开启。 53 | 54 | #### 配置服务器和客户端使用 SSL/TLS 55 | 56 | TCP 客户端和服务器可以配置使用TLS([安全传输层协议](http://baike.baidu.com/link?url=PPiSbb4Qa9EBJQ8PABddBZGoD1jx28958c9gksFY92a0BHpWJEgLau-pF5xwMrhyB-5TlJeqJCk-ZZe0wllKTq))-TLS 的早期版本被称为 SSL。 57 | 58 | 无论使用 SSL/TLS服务器和客户端 Api 是相同的,是否启用,通过[NetClientOptions](http://vertx.io/docs/apidocs/io/vertx/core/net/NetClientOptions.html)或[NetServerOptions](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServerOptions.html)实例配置。 59 | 60 | ##### 在服务器上启用 SSL/TLS 61 | 62 | 通过[ssl](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServerOptions.html#setSsl-boolean-)启用 SSL/TLS. 63 | 64 | 默认是禁用的。 65 | 66 | ##### 为服务器指定密钥/证书 67 | 68 | SSL / TLS服务器通常提供证书给客户以验证他们的身份。 69 | 70 | 针对服务器的几种配置证书/密钥的方式: 71 | 72 | 第一种方法是通过指定 `Java` 密钥存储并包含证书和私钥的位置。 73 | 74 | Java 密钥存储库可以使用JDK附带的实用程序[keytool](http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html)工具管理。 75 | 此外应提供密钥存储库的密码: 76 | 77 | ``` 78 | NetServerOptions options = new NetServerOptions().setSsl(true).setKeyStoreOptions( 79 | new JksOptions(). 80 | setPath("/path/to/your/server-keystore.jks"). 81 | setPassword("password-of-your-keystore") 82 | ); 83 | NetServer server = vertx.createNetServer(options); 84 | ``` 85 | 86 | 或者,你可以把你自己的钥匙储存为一个缓冲区,直接提供: 87 | 88 | 89 | ``` 90 | Buffer myKeyStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/server-keystore.jks"); 91 | JksOptions jksOptions = new JksOptions(). 92 | setValue(myKeyStoreAsABuffer). 93 | setPassword("password-of-your-keystore"); 94 | NetServerOptions options = new NetServerOptions(). 95 | setSsl(true). 96 | setKeyStoreOptions(jksOptions); 97 | NetServer server = vertx.createNetServer(options); 98 | ``` 99 | 100 | 还可以以类似 `JKS` 方式 `PKCS #12` 格式 (http://en.wikipedia.org/wiki/PKCS_12)密钥存储加载密钥/证书,通常具有.pfx或.p12扩展名: 101 | 102 | ``` 103 | NetServerOptions options = new NetServerOptions().setSsl(true).setPfxKeyCertOptions( 104 | new PfxOptions(). 105 | setPath("/path/to/your/server-keystore.pfx"). 106 | setPassword("password-of-your-keystore") 107 | ); 108 | NetServer server = vertx.createNetServer(options); 109 | ``` 110 | 111 | 此外支持缓冲区配置: 112 | 113 | ``` 114 | Buffer myKeyStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/server-keystore.pfx"); 115 | PfxOptions pfxOptions = new PfxOptions(). 116 | setValue(myKeyStoreAsABuffer). 117 | setPassword("password-of-your-keystore"); 118 | NetServerOptions options = new NetServerOptions(). 119 | setSsl(true). 120 | setPfxKeyCertOptions(pfxOptions); 121 | NetServer server = vertx.createNetServer(options); 122 | ``` 123 | 124 | 另一种方式,分别使用`.pem`文件提供服务器私钥和证书。 125 | 126 | ``` 127 | NetServerOptions options = new NetServerOptions().setSsl(true).setPemKeyCertOptions( 128 | new PemKeyCertOptions(). 129 | setKeyPath("/path/to/your/server-key.pem"). 130 | setCertPath("/path/to/your/server-cert.pem") 131 | ); 132 | NetServer server = vertx.createNetServer(options); 133 | ``` 134 | 135 | 此外支持缓冲区配置: 136 | 137 | ``` 138 | Buffer myKeyAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/server-key.pem"); 139 | Buffer myCertAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/server-cert.pem"); 140 | PemKeyCertOptions pemOptions = new PemKeyCertOptions(). 141 | setKeyValue(myKeyAsABuffer). 142 | setCertValue(myCertAsABuffer); 143 | NetServerOptions options = new NetServerOptions(). 144 | setSsl(true). 145 | setPemKeyCertOptions(pemOptions); 146 | NetServer server = vertx.createNetServer(options); 147 | ``` 148 | 149 | 请牢记,pem 的配置, 私钥是不加密的。 150 | 151 | ##### 指定信任服务器 152 | 153 | SSL / TLS服务器使用证书授权可以以验证客户端的身份。 154 | 155 | 几种针对服务器的证书授权的配置方法: 156 | 157 | 158 | 此外应提供密钥存储库的密码: 159 | 160 | Java trust存储库可以使用 JDK附带的实用程序[keytool](http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html)工具管理。 161 | 162 | 此外应提供trust存储库的密码: 163 | 164 | ``` 165 | NetServerOptions options = new NetServerOptions(). 166 | setSsl(true). 167 | setClientAuth(ClientAuth.REQUIRED). 168 | setTrustStoreOptions( 169 | new JksOptions(). 170 | setPath("/path/to/your/truststore.jks"). 171 | setPassword("password-of-your-truststore") 172 | ); 173 | NetServer server = vertx.createNetServer(options); 174 | ``` 175 | 176 | 或者,你可以把你自己的trust储存为一个缓冲区,直接提供: 177 | 178 | ``` 179 | Buffer myTrustStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/truststore.jks"); 180 | NetServerOptions options = new NetServerOptions(). 181 | setSsl(true). 182 | setClientAuth(ClientAuth.REQUIRED). 183 | setTrustStoreOptions( 184 | new JksOptions(). 185 | setValue(myTrustStoreAsABuffer). 186 | setPassword("password-of-your-truststore") 187 | ); 188 | NetServer server = vertx.createNetServer(options); 189 | ``` 190 | 191 | 还可以以类似 `JKS` 方式 `PKCS #12` 格式 (http://en.wikipedia.org/wiki/PKCS_12) `trust` 存储加载密钥/证书,通常具有.pfx或.p12扩展名: 192 | 193 | ``` 194 | NetServerOptions options = new NetServerOptions(). 195 | setSsl(true). 196 | setClientAuth(ClientAuth.REQUIRED). 197 | setPfxTrustOptions( 198 | new PfxOptions(). 199 | setPath("/path/to/your/truststore.pfx"). 200 | setPassword("password-of-your-truststore") 201 | ); 202 | NetServer server = vertx.createNetServer(options); 203 | ``` 204 | 205 | 此外支持缓冲区配置: 206 | 207 | ``` 208 | Buffer myTrustStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/truststore.pfx"); 209 | NetServerOptions options = new NetServerOptions(). 210 | setSsl(true). 211 | setClientAuth(ClientAuth.REQUIRED). 212 | setPfxTrustOptions( 213 | new PfxOptions(). 214 | setValue(myTrustStoreAsABuffer). 215 | setPassword("password-of-your-truststore") 216 | ); 217 | NetServer server = vertx.createNetServer(options); 218 | ``` 219 | 220 | 221 | 另一种方式,使用列表的.pem文件提供服务器证书授权 222 | 223 | ``` 224 | NetServerOptions options = new NetServerOptions(). 225 | setSsl(true). 226 | setClientAuth(ClientAuth.REQUIRED). 227 | setPemTrustOptions( 228 | new PemTrustOptions(). 229 | addCertPath("/path/to/your/server-ca.pem") 230 | ); 231 | NetServer server = vertx.createNetServer(options); 232 | ``` 233 | 234 | 此外支持缓冲区配置: 235 | 236 | ``` 237 | Buffer myCaAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/server-ca.pfx"); 238 | NetServerOptions options = new NetServerOptions(). 239 | setSsl(true). 240 | setClientAuth(ClientAuth.REQUIRED). 241 | setPemTrustOptions( 242 | new PemTrustOptions(). 243 | addCertValue(myCaAsABuffer) 244 | ); 245 | NetServer server = vertx.createNetServer(options); 246 | ``` 247 | 248 | ##### 在客户端上启用 SSL/TLS 249 | 250 | Net 客户端也可以轻松地配置为使用 SSL。他们有相同的 API,当使用 SSL时 使用的是标准的sockets。 251 | 252 | NetClient调用setSSL(true) 函数启用 SSL。 253 | 254 | ##### 客户端信任配置 255 | 256 | 在客户端,如果[trustALl](http://vertx.io/docs/apidocs/io/vertx/core/net/ClientOptionsBase.html#setTrustAll-boolean-)设置为 true,客户端将信任所有的服务器证书。连接仍将被加密,但这种模式是易受攻击的。请谨慎使用。默认值为 false。 257 | 258 | ``` 259 | NetClientOptions options = new NetClientOptions(). 260 | setSsl(true). 261 | setTrustAll(true); 262 | NetClient client = vertx.createNetClient(options); 263 | ``` 264 | 265 | 如果未设置[trustAll](http://vertx.io/docs/apidocs/io/vertx/core/net/ClientOptionsBase.html#setTrustAll-boolean-),客户端必须配置trust store 和应该包含该客户端信任的服务器证书。 266 | 267 | 同服务器配置,配置客户端信任可以分几个方面: 268 | 269 | 第一种方法是通过指定包含证书授权 Java trust-store 的位置。 270 | 271 | 这只是标准 Java 密钥库,密钥存储与服务器端相同。由 [jks options](http://vertx.io/docs/apidocs/io/vertx/core/net/JksOptions.html) 使用函数[path](http://vertx.io/docs/apidocs/io/vertx/core/net/JksOptions.html#setPath-java.lang.String-)设置的客户端trust-store位置。如果服务器不是客户端信任存储区中的连接过程中提供的证书,则连接尝试不会成功。 272 | 273 | ``` 274 | NetClientOptions options = new NetClientOptions(). 275 | setSsl(true). 276 | setTrustStoreOptions( 277 | new JksOptions(). 278 | setPath("/path/to/your/truststore.jks"). 279 | setPassword("password-of-your-truststore") 280 | ); 281 | NetClient client = vertx.createNetClient(options); 282 | ``` 283 | 284 | 此外支持缓冲区配置: 285 | 286 | ``` 287 | Buffer myTrustStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/truststore.jks"); 288 | NetClientOptions options = new NetClientOptions(). 289 | setSsl(true). 290 | setTrustStoreOptions( 291 | new JksOptions(). 292 | setValue(myTrustStoreAsABuffer). 293 | setPassword("password-of-your-truststore") 294 | ); 295 | NetClient client = vertx.createNetClient(options); 296 | ``` 297 | 298 | 还可以以类似 `JKS` 方式 `PKCS #12` 格式 (http://en.wikipedia.org/wiki/PKCS_12) `trust` 存储加载密钥/证书,通常具有.pfx或.p12扩展名: 299 | 300 | ``` 301 | NetClientOptions options = new NetClientOptions(). 302 | setSsl(true). 303 | setPfxTrustOptions( 304 | new PfxOptions(). 305 | setPath("/path/to/your/truststore.pfx"). 306 | setPassword("password-of-your-truststore") 307 | ); 308 | NetClient client = vertx.createNetClient(options); 309 | ``` 310 | 此外支持缓冲区配置: 311 | 312 | ``` 313 | Buffer myTrustStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/truststore.pfx"); 314 | NetClientOptions options = new NetClientOptions(). 315 | setSsl(true). 316 | setPfxTrustOptions( 317 | new PfxOptions(). 318 | setValue(myTrustStoreAsABuffer). 319 | setPassword("password-of-your-truststore") 320 | ); 321 | NetClient client = vertx.createNetClient(options); 322 | ``` 323 | 324 | 另一种方式,使用列表的.pem文件提供服务器证书授权 325 | 326 | ``` 327 | NetClientOptions options = new NetClientOptions(). 328 | setSsl(true). 329 | setPemTrustOptions( 330 | new PemTrustOptions(). 331 | addCertPath("/path/to/your/ca-cert.pem") 332 | ); 333 | NetClient client = vertx.createNetClient(options); 334 | ``` 335 | 336 | 此外支持缓冲区配置: 337 | 338 | ``` 339 | Buffer myTrustStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/ca-cert.pem"); 340 | NetClientOptions options = new NetClientOptions(). 341 | setSsl(true). 342 | setPemTrustOptions( 343 | new PemTrustOptions(). 344 | addCertValue(myTrustStoreAsABuffer) 345 | ); 346 | NetClient client = vertx.createNetClient(options); 347 | ``` 348 | 349 | ##### 为客户端指定密钥/证书 350 | 351 | 如果服务器要求客户端身份验证,然后连接时,客户端必须向服务器提交它自己的证书。客户端可以配置几个方面: 352 | 353 | 第一种方法是通过指定 Java 密钥库包含密钥和证书的位置。这是只是常规 Java 的密钥存储库。客户端密钥库位置是通过使用函数[path](http://vertx.io/docs/apidocs/io/vertx/core/net/JksOptions.html#setPath-java.lang.String-)上[jks options](http://vertx.io/docs/apidocs/io/vertx/core/net/JksOptions.html)设置. 354 | 355 | ``` 356 | NetClientOptions options = new NetClientOptions().setSsl(true).setKeyStoreOptions( 357 | new JksOptions(). 358 | setPath("/path/to/your/client-keystore.jks"). 359 | setPassword("password-of-your-keystore") 360 | ); 361 | NetClient client = vertx.createNetClient(options); 362 | ``` 363 | 364 | 此外支持缓冲区配置: 365 | 366 | ``` 367 | Buffer myKeyStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/client-keystore.jks"); 368 | JksOptions jksOptions = new JksOptions(). 369 | setValue(myKeyStoreAsABuffer). 370 | setPassword("password-of-your-keystore"); 371 | NetClientOptions options = new NetClientOptions(). 372 | setSsl(true). 373 | setKeyStoreOptions(jksOptions); 374 | NetClient client = vertx.createNetClient(options); 375 | ``` 376 | 377 | 还可以以类似 `JKS` 方式 `PKCS #12` 格式 (http://en.wikipedia.org/wiki/PKCS_12) `trust` 存储加载密钥/证书,通常具有.pfx或.p12扩展名: 378 | 379 | ``` 380 | NetClientOptions options = new NetClientOptions().setSsl(true).setPfxKeyCertOptions( 381 | new PfxOptions(). 382 | setPath("/path/to/your/client-keystore.pfx"). 383 | setPassword("password-of-your-keystore") 384 | ); 385 | NetClient client = vertx.createNetClient(options); 386 | ``` 387 | 388 | 此外支持缓冲区配置: 389 | 390 | ``` 391 | Buffer myKeyStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/client-keystore.pfx"); 392 | PfxOptions pfxOptions = new PfxOptions(). 393 | setValue(myKeyStoreAsABuffer). 394 | setPassword("password-of-your-keystore"); 395 | NetClientOptions options = new NetClientOptions(). 396 | setSsl(true). 397 | setPfxKeyCertOptions(pfxOptions); 398 | NetClient client = vertx.createNetClient(options); 399 | ``` 400 | 401 | 另一种方式,分别使用`.pem`文件提供服务器私钥和证书。 402 | 403 | ``` 404 | NetClientOptions options = new NetClientOptions().setSsl(true).setPemKeyCertOptions( 405 | new PemKeyCertOptions(). 406 | setKeyPath("/path/to/your/client-key.pem"). 407 | setCertPath("/path/to/your/client-cert.pem") 408 | ); 409 | NetClient client = vertx.createNetClient(options); 410 | ``` 411 | 412 | 此外支持缓冲区配置: 413 | 414 | ``` 415 | Buffer myKeyAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/client-key.pem"); 416 | Buffer myCertAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/client-cert.pem"); 417 | PemKeyCertOptions pemOptions = new PemKeyCertOptions(). 418 | setKeyValue(myKeyAsABuffer). 419 | setCertValue(myCertAsABuffer); 420 | NetClientOptions options = new NetClientOptions(). 421 | setSsl(true). 422 | setPemKeyCertOptions(pemOptions); 423 | NetClient client = vertx.createNetClient(options); 424 | ``` 425 | 426 | 请牢记,pem 的配置, 私钥是不加密的。 427 | 428 | ##### 吊销认证授权 429 | 430 | 被吊销的证书不再应信任,信任可以配置为使用证书吊销列表 (CRL)。[crlPath](http://vertx.io/docs/apidocs/io/vertx/core/net/NetClientOptions.html#addCrlPath-java.lang.String-)配置要使用的 crl 列表: 431 | 432 | ``` 433 | NetClientOptions options = new NetClientOptions(). 434 | setSsl(true). 435 | setTrustStoreOptions(trustOptions). 436 | addCrlPath("/path/to/your/crl.pem"); 437 | NetClient client = vertx.createNetClient(options); 438 | ``` 439 | 440 | 此外支持缓冲区配置: 441 | 442 | ``` 443 | Buffer myCrlAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/crl.pem"); 444 | NetClientOptions options = new NetClientOptions(). 445 | setSsl(true). 446 | setTrustStoreOptions(trustOptions). 447 | addCrlValue(myCrlAsABuffer); 448 | NetClient client = vertx.createNetClient(options); 449 | ``` 450 | 451 | ##### 配置加密套件 452 | 453 | 默认情况下,TLS配置将使用JVM运行Vert.x.的加密套件这种密码套件可以用一组启用密码进行配置: 454 | 455 | ``` 456 | NetServerOptions options = new NetServerOptions(). 457 | setSsl(true). 458 | setKeyStoreOptions(keyStoreOptions). 459 | addEnabledCipherSuite("ECDHE-RSA-AES128-GCM-SHA256"). 460 | addEnabledCipherSuite("ECDHE-ECDSA-AES128-GCM-SHA256"). 461 | addEnabledCipherSuite("ECDHE-RSA-AES256-GCM-SHA384"). 462 | addEnabledCipherSuite("CDHE-ECDSA-AES256-GCM-SHA384"); 463 | NetServer server = vertx.createNetServer(options); 464 | ``` 465 | 466 | 加密套件可以在NetServerOptions或NetClientOptions配置中指定。 467 | 468 | -------------------------------------------------------------------------------- /TCP/TCP 服务器.md: -------------------------------------------------------------------------------- 1 | # 编写 TCP 服务器 2 | 3 | #### 创建 TCP 服务器 4 | 5 | 使用最简单的方法来创建一个 TCP 服务器,使用所有默认选项如下所示: 6 | 7 | ``` 8 | NetServer server = vertx.createNetServer(); 9 | ``` 10 | 11 | 12 | #### 配置 TCP 服务器 13 | 14 | 如果你不想默认值,可以将服务器配置通过传入一个[NetServerOptions](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServerOptions.html)实例来创建它: 15 | 16 | ``` 17 | NetServerOptions options = new NetServerOptions().setPort(4321); 18 | NetServer server = vertx.createNetServer(options); 19 | ``` 20 | #### 启动服务器监听 21 | 22 | 使用[listen](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServer.html#listen--)告诉服务监听传入的请求 23 | 24 | 告诉要听的主机和端口作为选项中指定的服务器: 25 | 26 | 需要在选项(`NetServerOptions`)中指定的主机和端口: 27 | 28 | ``` 29 | NetServer server = vertx.createNetServer(); 30 | server.listen(); 31 | ``` 32 | 33 | 或在调用listen中指定的主机和端口,忽略`NetServerOptions`配置: 34 | 35 | ``` 36 | NetServer server = vertx.createNetServer(); 37 | server.listen(1234, "localhost"); 38 | ``` 39 | 40 | 默认主机是`0.0.0.0`,意味着 '监听所有可用的地址' ,默认端口是0,这是一个特殊值,告诉服务器随机找一个未使用的本地端口使用。 41 | 42 | 真实的绑定是异步的,所以服务器可能不会实际被侦听,直到有一段时间后,调用返回。 43 | 44 | 如果想要listen实际监听后通知你,可以提供listen调用处理程序。例如: 45 | 46 | ``` 47 | NetServer server = vertx.createNetServer(); 48 | server.listen(1234, "localhost", res -> { 49 | if (res.succeeded()) { 50 | System.out.println("Server is now listening!"); 51 | } else { 52 | System.out.println("Failed to bind!"); 53 | } 54 | }); 55 | ``` 56 | 57 | #### 监听随机端口 58 | 59 | 如果`0`用作的监听端口,则服务器将找到一个未使用的随机端口监听。 60 | 61 | 若要找出服务器正在监听的真正端口,您可以调用[actualPort](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServer.html#actualPort--). 62 | 63 | ``` 64 | NetServer server = vertx.createNetServer(); 65 | server.listen(0, "localhost", res -> { 66 | if (res.succeeded()) { 67 | System.out.println("Server is now listening on actual port: " + server.actualPort()); 68 | } else { 69 | System.out.println("Failed to bind!"); 70 | } 71 | }); 72 | ``` 73 | 74 | 75 | #### 传入连接通知 76 | 77 | 若要连接时通知您需要设置[connectHandler](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServer.html#connectHandler-io.vertx.core.Handler-): 78 | 79 | ``` 80 | NetServer server = vertx.createNetServer(); 81 | server.connectHandler(socket -> { 82 | // Handle the connection in here 83 | }); 84 | ``` 85 | 86 | 当进行连接时的处理程序将调用[Netsocket](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html)实例。 87 | 88 | 89 | 这是一个类似于socket-like的接口的真实连接,并且允许你读写数据以及做其他各种类似的事情,比如关闭套接字。 90 | 91 | #### 从Socket读取数据 92 | 93 | 从socket读取数据要在socket上设置[handler](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#handler-io.vertx.core.Handler-)。 94 | 95 | 每次在socket上接收到数据Buffer实例,将调用此处理程序。 96 | 97 | ``` 98 | NetServer server = vertx.createNetServer(); 99 | server.connectHandler(socket -> { 100 | socket.handler(buffer -> { 101 | System.out.println("I received some bytes: " + buffer.length()); 102 | }); 103 | }); 104 | ``` 105 | 106 | #### 数据写入socket 107 | 108 | 使用[write](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#write-io.vertx.core.buffer.Buffer-)写到socket. 109 | 110 | ``` 111 | Buffer buffer = Buffer.buffer().appendFloat(12.34f).appendInt(123); 112 | socket.write(buffer); 113 | 114 | // Write a string in UTF-8 encoding 115 | socket.write("some data"); 116 | 117 | // Write a string using the specified encoding 118 | socket.write("some data", "UTF-16"); 119 | ``` 120 | 121 | 写操作是异步的,调用返回之后可能不会发生。 122 | 123 | ####关闭的处理程序(handler) 124 | 125 | 如果你想要关闭socket时得到通知,可以设置[closeHandler](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#closeHandler-io.vertx.core.Handler-) : 126 | 127 | ``` 128 | socket.closeHandler(v -> { 129 | System.out.println("The socket has been closed"); 130 | }); 131 | ``` 132 | 133 | #### 处理异常 134 | 135 | 您可以设置[exceptionHandler](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#exceptionHandler-io.vertx.core.Handler-)接收socket发生的任何异常。 136 | 137 | #### Event bus写handler 138 | 139 | 每个socket自动注册event bus上的handler,当这个handler接收到任何buffers时,它会将它们写入到本身。 140 | 141 | 这使您可以将数据写到socket,它可能是在完全不同的verticle或甚至在不同的 Vert.x 实例,通过将buffers发送到该处理程序的地址。 142 | 143 | 由[writeHandlerID](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#writeHandlerID--)给出了处理程序的地址 144 | 145 | #### 本地和远程地址 146 | 147 | 可以使用[localAddress](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#localAddress--)检索[NetSocket](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html)的本地地址. 148 | 149 | 可以使用[remoteAddress](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#remoteAddress--)检索远程地址 (即地址连接的另一端) 的[NetSocket](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html). 150 | 151 | #### 从classpath发送文件或资源 152 | 153 | 直接使用[sendFile](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#sendFile-java.lang.String-)就可以将文件写入socket。这是非常有效的发送文件的方法,因为它可以由操作系统内核直接支持。 154 | 155 | ``` 156 | socket.sendFile("myfile.dat"); 157 | ``` 158 | 159 | #### Streaming sockets 160 | 161 | NetSocket的实例也是ReadStream和WriteStream的实例,因此他们可以被用于泵送数据,可以从其他的读和写streams。 162 | 163 | 详细信息,请参阅Streams章。 164 | 165 | #### 升级到 SSL/TLS 连接 166 | 167 | 非 `SSL/TLS` 连接可以使用[upgradeToSsl](http://vertx.io/docs/apidocs/io/vertx/core/net/NetSocket.html#upgradeToSsl-io.vertx.core.Handler-)升级到 `SSL/TLS`。 168 | 169 | 服务器或客户端必须配置为 `SSL/TLS` 才能正常工作。详细信息请参阅关于 `SSL/TLS` 章节。 170 | 171 | #### 关闭一个 TCP 服务器 172 | 173 | 叫[close](http://vertx.io/docs/apidocs/io/vertx/core/net/NetServer.html#close--)来关闭服务器。关闭服务器关闭任何打开的连接,并释放所有的服务器资源。 174 | 175 | 关闭是异步的,可能无法立即返回。如果你想要关闭已完成然后通知,可以通过handler做到。 176 | 177 | 当关闭已全面完成,然后将调用此处理程序。 178 | 179 | ``` 180 | server.close(res -> { 181 | if (res.succeeded()) { 182 | System.out.println("Server is now closed"); 183 | } else { 184 | System.out.println("close failed"); 185 | } 186 | }); 187 | ``` 188 | 189 | #### Verticles 自动清理 190 | 191 | 如果您正在从 `verticles`内创建 `TCP` 服务器和客户端,`verticle`取消部署时这些服务器和客户端将被自动关闭。 192 | 193 | #### Scaling - sharing TCP 服务器 194 | 195 | 任何TCP服务器的处理器总是在相同的事件循环线程执行。 196 | 197 | 这意味着,如果在多核的服务器上运行,而你只部署一个实例,那么最多使用一个核心。 198 | 199 | 为了利用你的服务器更多的核心,你将需要部署服务器的多个实例。 200 | 201 | 您可以以编程方式在代码中实例化多个实例: 202 | 203 | ``` 204 | for (int i = 0; i < 10; i++) { 205 | NetServer server = vertx.createNetServer(); 206 | server.connectHandler(socket -> { 207 | socket.handler(buffer -> { 208 | // Just echo back the data 209 | socket.write(buffer); 210 | }); 211 | }); 212 | server.listen(1234, "localhost"); 213 | } 214 | ``` 215 | 216 | 或者,如果您正在使用verticles你可以简单地通过使用命令行选项`-instances`部署服务器verticle的多个实例: 217 | 218 | ``` 219 | vertx run com.mycompany.MyVerticle -instances 10 220 | ``` 221 | 222 | 或以编程方式部署verticle 223 | 224 | ``` 225 | DeploymentOptions options = new DeploymentOptions().setInstances(10); 226 | vertx.deployVerticle("com.mycompany.MyVerticle", options); 227 | ``` 228 | 229 | 一旦你这样做,你会发现echo服务器的功能与以前的功能相同,但可以利用您在您的服务器上的所有核心,可以处理更多的工作。 230 | 231 | 在这一点上你可能会问自己' 你怎么能有多个服务器监听同一主机和端口?尝试部署多个实例,肯定会端口冲突?' 232 | 233 | Vert.x 确实有点神奇,如: 234 | 235 | 当你在同一个主机上部署另一个服务器,作为一个现有的服务器,它实际上并没有尝试在同一个主机/端口上创建一个新的服务器。 236 | 237 | 相反它内部维护只是一台服务器,将连接通过循环的方式分配处理程序。 238 | 239 | 因此 Vert.x TCP 服务部署可以超过可用CPU内核,每个实例是单个线程。 240 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "layout", 4 | "baidu", 5 | "edit-link", 6 | "tbfed-pagefooter", 7 | "ga" 8 | ], 9 | "pluginsConfig": { 10 | "headerPath": "layouts/header.html", 11 | "footerPath": "layouts/footer.html", 12 | "baidu": { 13 | "token": "2d97e54587fe0a988606550c9b115a6b" 14 | }, 15 | "tbfed-pagefooter": { 16 | "copyright":"Copyright © quanke.name 2016", 17 | "modify_label": "该文件修订时间:", "modify_format": "YYYY-MM-DD HH:mm:ss" } , 18 | "edit-link": { 19 | "base": "https://github.com/USER/REPO/edit/BRANCH", "label": "Edit This Page" }, 20 | "ga": { 21 | "token": "UA-82833335-1" 22 | } 23 | 24 | }, 25 | "links": { 26 | "sidebar": { 27 | "Home": "http://quanke.name" 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quanke/vert-x-core-manual-for-java/56702e9ff519c1d625d445e6bebd888e0c027be1/cover.jpg -------------------------------------------------------------------------------- /layouts/footer.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quanke/vert-x-core-manual-for-java/56702e9ff519c1d625d445e6bebd888e0c027be1/layouts/footer.html -------------------------------------------------------------------------------- /layouts/header.html: -------------------------------------------------------------------------------- 1 | 欢迎关注quanke.name 2 | 3 | -------------------------------------------------------------------------------- /styles/ebook.css: -------------------------------------------------------------------------------- 1 | /* CSS for ebook */ 2 | -------------------------------------------------------------------------------- /styles/mobi.css: -------------------------------------------------------------------------------- 1 | /* CSS for mobi */ 2 | -------------------------------------------------------------------------------- /styles/pdf.css: -------------------------------------------------------------------------------- 1 | /* CSS for pdf */ 2 | -------------------------------------------------------------------------------- /styles/website.css: -------------------------------------------------------------------------------- 1 | /* CSS for website */ 2 | -------------------------------------------------------------------------------- /verticles/Context对象.md: -------------------------------------------------------------------------------- 1 | # Context对象 2 | 当Vert.x提供一个事件的处理程序或调用[Verticle](http://vertx.io/docs/apidocs/io/vertx/core/Verticle.html)的开始或停止的方法,执行与`Context`相关联。一般Context是event-loop context 绑定特定的事件循环线程。因此,对于这方面的执行总是发生在该完全相同的事件循环线程。在worker verticles和运行内嵌阻止代码worker context的情况下将使用一个线程从worker线程池的执行关联。 3 | 4 | 若要获得context,请使用getOrCreateContext方法: 5 | 6 | ``` 7 | Context context = vertx.getOrCreateContext(); 8 | ``` 9 | 10 | 如果当前线程具有一个与它相关联的context,它重复使用context对象。如果不创建新实例的context。您可以测试您取得的context的类型: 11 | 12 | ``` 13 | Context context = vertx.getOrCreateContext(); 14 | if (context.isEventLoopContext()) { 15 | System.out.println("Context attached to Event Loop"); 16 | } else if (context.isWorkerContext()) { 17 | System.out.println("Context attached to Worker Thread"); 18 | } else if (context.isMultiThreadedWorkerContext()) { 19 | System.out.println("Context attached to Worker Thread - multi threaded worker"); 20 | } else if (! Context.isOnVertxThread()) { 21 | System.out.println("Context not attached to a thread managed by vert.x"); 22 | } 23 | ``` 24 | 25 | 当您取得context对象时,您可以以异步方式在此context中运行代码。换句话说,您提交相同的context,但后来将最终运行任务: 26 | 27 | ``` 28 | vertx.getOrCreateContext().runOnContext( (v) -> { 29 | System.out.println("This will be executed asynchronously in the same context"); 30 | }); 31 | ``` 32 | 33 | 当几个处理程序在相同的context中运行时,他们可能想要分享数据。context对象提供方法来存储和获取在context中共享的数据。例如,它可以让你通过一些行动[runOnContext](http://vertx.io/docs/apidocs/io/vertx/core/Context.html#runOnContext-io.vertx.core.Handler-)运行数据: 34 | 35 | 36 | ``` 37 | final Context context = vertx.getOrCreateContext(); 38 | context.put("data", "hello"); 39 | context.runOnContext((v) -> { 40 | String hello = context.get("data"); 41 | }); 42 | ``` 43 | 44 | context对象还可让您使用的config方法访问verticle配置。 45 | -------------------------------------------------------------------------------- /verticles/Vert_x 退出.md: -------------------------------------------------------------------------------- 1 | # Vert.x 退出 2 | 3 | 由 Vert.x 实例维护的线程不是守护程序线程,从而防止 JVM 退出。 4 | 5 | 如果你嵌入 Vert.x 和你已完成了,你可以调用[close](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#close--)来关闭它。 6 | 7 | 这将关闭所有的内部线程池和关闭其他的资源,让 JVM 退出。 8 | -------------------------------------------------------------------------------- /verticles/Verticles 自动清理.md: -------------------------------------------------------------------------------- 1 | # Verticles 自动清理 2 | 3 | 4 | 如果您正在从 verticles 内创建的计时器,这些计时器将被自动关闭verticle undeployed。 -------------------------------------------------------------------------------- /verticles/Verticle类型.md: -------------------------------------------------------------------------------- 1 | # Verticle类型 2 | 3 | 4 | 有三种不同类型的 verticles: 5 | 6 | ##### 标准 Verticles 7 | 这些都是最常见和最有用的类型 — — 他们总是使用事件循环线程执行。更多讨论在下一节。 8 | 9 | ##### Worker Verticles 10 | 一个实例是永远不会有多个线程并发执行。 11 | 12 | ##### 多线程的worker verticles 13 | 一个实例可以由多个线程同时执行。 14 | 15 | #### 标准 verticles 16 | 标准verticles当创建和调用start方法时分配一个event loop。调用执行都在相同的event loop上。 17 | 18 | 这意味着我们可以保证您的verticles实例中的所有代码总是都执行相同的事件循环上 (只要你不调用它自己创建的线程!)。 19 | 20 | 这意味着可以在程序里作为单线程编写所有的代码,把担心线程和扩展的问题交给Vert.x。没有更多令人担忧的同步和更多不稳定的问题,也避免了多线程死锁的问题。 21 | 22 | 23 | #### Worker verticles 24 | 25 | Worker verticles就像标准的verticles一样,但不使用事件循环执行,从 Vert.x worker线程池使用一个线程。 26 | 27 | worker verticles 专为调用阻塞的代码,因为他们不会阻止任何事件循环。 28 | 29 | 如果你不想使用worker verticles运行阻塞的代码,可以在事件循环上直接运行内联阻塞代码。 30 | 31 | 如果您要以worker verticles的方式部署verticle,需要调用 [setWorker](http://vertx.io/docs/apidocs/io/vertx/core/DeploymentOptions.html#setWorker-boolean-). 32 | 33 | ``` 34 | DeploymentOptions options = new DeploymentOptions().setWorker(true); 35 | vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options); 36 | ``` 37 | 38 | Worker verticle实例永远不会有多个线程并发执行 ,但可以在不同的时间由不同的线程执行。 39 | 40 | ##### 多线程Worker verticles 41 | 42 | 多线程的worker verticle就像正常worker verticle,但它是可以由不同的线程同时执行。 43 | 44 | *警告! 45 | 多线程的worker verticle 是一项高级的功能,大多数应用程序会对他们来说没有必要。因为在这些 verticles 并发,你必须非常小心,使用标准的 Java 技术的多线程编程,以保持verticle一致状态。* -------------------------------------------------------------------------------- /verticles/Verticle隔离组.md: -------------------------------------------------------------------------------- 1 | # Verticle隔离组 2 | 默认情况下,Vert.x 具有flat classpath。即,当 Vert.x 部署 verticles 使用当前类加载器-它不会创建一个新。在大多数情况下这是最简单、 最明确和理智的事情。 3 | 4 | 然而,在某些情况下,您可能想要部署verticle,所以在您的应用程序verticle的类是孤立于其他。 5 | 6 | 这可能并非如此,例如,如果您要部署两个不同版本的同一个 Vert.x 实例,类名相同的verticle或如果你有两个不同的 verticles,使用不同版本的相同的 jar 库。 7 | 8 | 隔离组,使用[setisolatedclasses](http://vertx.io/docs/apidocs/io/vertx/core/DeploymentOptions.html#setIsolatedClasses-java.util.List-) - 条目名称可以是完整类名,如`com.mycompany.myproject.engine.myclass`或它可以是一个通配符,将匹配任何包中的类和任何子的软件包,例如`com.mycompany.myproject.*`将匹配`com.mycompany.myproject`包中的任何类或任何子包。 9 | 10 | 请注意,只有匹配的将隔离 — — 任何其他类将由当前的类加载器加载。 11 | 12 | 也可以与setExtraClasspath提供附加的类路径条目,所以如果你想要加载的类或资源,已经不是目前的主要的类路径上你可以添加这。 13 | 14 | 如果你想加载尚不存在的主要类路径类或资源,你可以使用[setExtraClasspath](http://vertx.io/docs/apidocs/io/vertx/core/DeploymentOptions.html#setExtraClasspath-java.util.List-) 15 | 16 | *警告! 17 | 谨慎使用此功能。类加载程序是一罐蠕虫,增加调试困难,除其他事项外。* 18 | 19 | 这里是一个使用隔离组隔离verticle deployment的示例。 20 | 21 | 22 | ``` 23 | DeploymentOptions options = new DeploymentOptions().setIsolationGroup("mygroup"); 24 | options.setIsolatedClasses(Arrays.asList("com.mycompany.myverticle.*", 25 | "com.mycompany.somepkg.SomeClass", "org.somelibrary.*")); 26 | vertx.deployVerticle("com.mycompany.myverticle.VerticleClass", options); 27 | ``` 28 | -------------------------------------------------------------------------------- /verticles/verticles.md: -------------------------------------------------------------------------------- 1 | # Verticles 2 | 3 | Vert.x 带有一个简单、 可扩展,actor-like 开箱即用,你可以用来节省您编写您自己的部署和并发模型。 4 | 5 | 此模型是完全可选的, 如果你不想去用,Vert.x 不会强制您以这种方式创建应用程序。 6 | 7 | 该模型并不要求是一个严格的[actor-model](http://my.oschina.net/quanke/blog/607173) 的实现,但它确实有相似之处,特别是对并发性,扩展和部署。 8 | 9 | 若要使用此模型,把代码设置为**verticles**. 10 | 11 | Verticles 是代码的得到部署和运行的 Vert.x 块。Verticles 可以使用任何 Vert.x 支持的语言编写,单个应用程序包含 verticles, 可以使用多种语言编写。 12 | 13 | 你可能会想,verticle有点像 [Actor Model](http://en.wikipedia.org/wiki/Actor_model) 中的actor。 14 | 15 | 应用通常是同一个 Vert.x 实例,同时由多个verticle实例组成。不同的verticle实例通过[event bus](http://vertx.io/docs/vertx-core/java/#event_bus)发送消息。 16 | 17 | -------------------------------------------------------------------------------- /verticles/verticle名称映射到一个verticle工厂的规则.md: -------------------------------------------------------------------------------- 1 | # verticle名称映射到一个verticle工厂的规则 2 | 当部署 verticle(s) 使用一个名称,该名称用于选择将实例化 verticle(s) 的实际verticle工厂。 3 | 4 | verticle的名称可以有前缀-它是一个字符串, 后跟一个冒号,它如果存在,则会被用来查找工厂,如 5 | 6 | ``` 7 | js:foo.js // Use the JavaScript verticle factory 8 | groovy:com.mycompany.SomeGroovyCompiledVerticle // Use the Groovy verticle factory 9 | service:com.mycompany:myorderservice // Uses the service verticle factory 10 | ``` 11 | 12 | 如果没有前缀,则 Vert.x 将寻找一个后缀和使用,例如查找工厂, 13 | 14 | ``` 15 | foo.js // Will also use the JavaScript verticle factory 16 | SomeScript.groovy // Will use the Groovy verticle factory 17 | ``` 18 | 19 | 如果没有前缀或后缀,则 Vert.x 会假设它是 Java 完整类名称 (FQCN),然后实例化。 20 | -------------------------------------------------------------------------------- /verticles/从命令行运行 Verticles.md: -------------------------------------------------------------------------------- 1 | # 从命令行运行 Verticles 2 | 使用 Vert.x ,通常可以直接在 Maven 或 Gradle 项目中添加 Vert.x core 库依赖。 3 | 4 | 还可以直接从命令行运行 Vert.x verticles。 5 | 6 | 做到这一点,你需要下载和安装一个 Vert.x ,并将安装的`bin`目录添加到`PATH`环境变量。还要确保`PATH`有 `Java 8 JDK`. 7 | 8 | *注意! 9 | JDK是需要支持的Java代码的即时编译。* 10 | 11 | 现在可以通过使用`vertx run`命令运行 verticles。这里有一些例子: 12 | 13 | ``` 14 | # Run a JavaScript verticle 15 | vertx run my_verticle.js 16 | 17 | # Run a Ruby verticle 18 | vertx run a_n_other_verticle.rb 19 | 20 | # Run a Groovy script verticle, clustered 21 | vertx run FooVerticle.groovy -cluster 22 | ``` 23 | 24 | 你甚至可以不编译直接运行Java源代码! 25 | 26 | ``` 27 | vertx run SomeJavaSourceFile.java 28 | ``` 29 | 30 | Vert.x 在运行之前会先编译Java源文件。这可以快速原型开发verticles,不需要设置 Maven 或 Gradle ! 31 | 32 | 更多信息,请在命令行上执行`vertx`。 33 | -------------------------------------------------------------------------------- /verticles/以编程方式部署 verticles.md: -------------------------------------------------------------------------------- 1 | # 以编程方式部署 verticles 2 | 3 | 4 | 5 | 使用deployVerticle方法部署verticles,指定verticles名,也可以把已经创建的verticles实例传递过来。 6 | 7 | *注意! 8 | 部署verticles实例只是 Java。* 9 | 10 | ``` 11 | Verticle myVerticle = new MyVerticle(); 12 | vertx.deployVerticle(myVerticle); 13 | ``` 14 | 15 | 您还可以通过指定verticles名称部署 verticles. 16 | 17 | verticles名称用于查找特定的[VerticleFactory](http://vertx.io/docs/apidocs/io/vertx/core/spi/VerticleFactory.html) ,将用来实例化实际verticles实例。 18 | 19 | 不同verticle工厂可用于实例化不同语言verticles和其他各种原因,例如装载服务和从Maven 在运行时得到verticles。 20 | 21 | 这允许您从 Vert.x 支持的任何语言编写的其他语言verticles部署 。 22 | 23 | 这里是 verticles 的部署一些不同类型的示例: 24 | 25 | ``` 26 | vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle"); 27 | 28 | // Deploy a JavaScript verticle 29 | vertx.deployVerticle("verticles/myverticle.js"); 30 | 31 | // Deploy a Ruby verticle verticle 32 | vertx.deployVerticle("verticles/my_verticle.rb"); 33 | ``` -------------------------------------------------------------------------------- /verticles/取消 verticle 部署.md: -------------------------------------------------------------------------------- 1 | # 取消 verticle 部署 2 | 部署可以通过[undeploy](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#undeploy-java.lang.String-)取消部署. 3 | 4 | 取消部署本身是异步的,所以如果想要在取消部署完成后通知,您可以部署指定完成处理程序: 5 | 6 | ``` 7 | vertx.undeploy(deploymentID, res -> { 8 | if (res.succeeded()) { 9 | System.out.println("Undeployed ok"); 10 | } else { 11 | System.out.println("Undeploy failed!"); 12 | } 13 | }); 14 | ``` 15 | 16 | -------------------------------------------------------------------------------- /verticles/在Verticle里访问环境变量.md: -------------------------------------------------------------------------------- 1 | # 在Verticle里访问环境变量。 2 | 3 | 使用 Java API 访问环境变量和系统属性: 4 | 5 | ``` 6 | System.getProperty("prop"); 7 | System.getenv("HOME"); 8 | ``` -------------------------------------------------------------------------------- /verticles/异步Verticle启动和停止.md: -------------------------------------------------------------------------------- 1 | # 异步Verticle启动和停止 2 | 3 | 实现异步启动 4 | 5 | 下面是一个示例: 6 | 7 | ``` 8 | public class MyVerticle extends AbstractVerticle { 9 | 10 | public void start(Future startFuture) { 11 | // Now deploy some other verticle: 12 | 13 | vertx.deployVerticle("com.foo.OtherVerticle", res -> { 14 | if (res.succeeded()) { 15 | startFuture.complete(); 16 | } else { 17 | startFuture.fail(); 18 | } 19 | }); 20 | } 21 | } 22 | ``` 23 | 24 | 同样地,也是 stop 方法也是异步。如果你想要做一些verticle的清理工作,这需要一些时间,则如此使用。 25 | 26 | ``` 27 | public class MyVerticle extends AbstractVerticle { 28 | 29 | public void start() { 30 | // Do something 31 | } 32 | 33 | public void stop(Future stopFuture) { 34 | obj.doSomethingThatTakesTime(res -> { 35 | if (res.succeeded()) { 36 | stopFuture.complete(); 37 | } else { 38 | stopFuture.fail(); 39 | } 40 | }); 41 | } 42 | } 43 | ``` 44 | 45 | *信息: 你不需要在启动一个verticle后手动取消部署子 verticles,在verticle的 stop 方法。当父verticle’s取消部署时,Vert.x 将自动取消部署任何子 verticles。* -------------------------------------------------------------------------------- /verticles/怎么样找到Verticle Factories.md: -------------------------------------------------------------------------------- 1 | # 怎么样找到Verticle Factories? 2 | 3 | 大多数的Verticle factories在 Vert.x 启动时从类路径中加载并注册。 4 | 5 | 你可以通过编程方式注册和注销Verticle factories,使用[registerVerticleFactory](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#registerVerticleFactory-io.vertx.core.spi.VerticleFactory-)和[unregisterVerticleFactory](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#unregisterVerticleFactory-io.vertx.core.spi.VerticleFactory-)。 -------------------------------------------------------------------------------- /verticles/执行定期和延迟的操作.md: -------------------------------------------------------------------------------- 1 | # 执行定期和延迟的操作 2 | 3 | 在Vert.x 中执行定期和延迟的操作是非常常见的。 4 | 5 | 在标准 verticles 中,不能使用thread sleep 引入延迟,这样会止事件循环线程。 6 | 7 | 相反,您可以使用 Vert.x 计时器。定时器可以一次性的计时器或定期的计时器。我们将讨论两个 8 | 9 | 10 | ##### 一次性的计时器 11 | 12 | 13 | 14 | 15 | 一个单次定时器有一定的延迟之后调用一个事件处理程序,以毫秒为单位表示。 16 | 17 | 使用[setTimeout](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#setTimer-long-io.vertx.core.Handler-)方法启动计时器, 18 | 19 | ``` 20 | long timerID = vertx.setTimer(1000, id -> { 21 | System.out.println("And one second later this is printed"); 22 | }); 23 | 24 | System.out.println("First this is printed"); 25 | ``` 26 | 27 | 返回值是一个唯一的定时器 id,以后可用于取消计时器。该处理器还通过定时器id。 28 | 29 | ##### 定期计时器 30 | 31 | 您还可以设置一个计时器来定期启动,通过使用[setPeriodic](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#setPeriodic-long-io.vertx.core.Handler-)方法。 32 | 33 | 会有一个初始延迟等于周期。 34 | 35 | setPeriodic的返回值是一个唯一的计时器的 id (long)。如果以后计时器需要取消,可以使用id。 36 | 37 | 传递到计时器事件处理程序的参数也是唯一的计时器的 id: 38 | 39 | 请记住,计时器会定期触发。如果你的周期性处理需要相当长的时间进行,你的计时器事件可以运行连续或更糟的是: 堆积。 40 | 41 | 42 | 在这种情况下,您应该考虑使用[setTimer](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html#setTimer-long-io.vertx.core.Handler-)替代。一旦您处理已完成,您可以设置下一个计时器。 43 | 44 | ``` 45 | long timerID = vertx.setPeriodic(1000, id -> { 46 | System.out.println("And every second this is printed"); 47 | }); 48 | 49 | System.out.println("First this is printed"); 50 | ``` 51 | 52 | #### 取消计时器 53 | 54 | 若要取消一个定期的计时器,请调用cancelTimer指定的计时器的 id。例如: 55 | 56 | ``` 57 | vertx.cancelTimer(timerID); 58 | ``` 59 | -------------------------------------------------------------------------------- /verticles/指定verticle实例数.md: -------------------------------------------------------------------------------- 1 | # 指定verticle实例数 2 | 3 | 在部署时verticle使用verticle的名称,可以指定您要部署的verticle实例的数目: 4 | 5 | ``` 6 | DeploymentOptions options = new DeploymentOptions().setInstances(16); 7 | vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options); 8 | ``` 9 | 10 | 用于跨多个内核轻松扩展。例如,您可能有 web 服务器verticle部署,服务器是多核的,你想要部署多个实例来充分利用所有核心。 -------------------------------------------------------------------------------- /verticles/等待部署完成.md: -------------------------------------------------------------------------------- 1 | # 等待部署完成 2 | 3 | Verticle部署是异步的,可能部署完成后才返回。 4 | 5 | 如果你想要部署完成后通知,您可以部署指定完成处理程序: 6 | 7 | ``` 8 | vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", res -> { 9 | if (res.succeeded()) { 10 | System.out.println("Deployment id is: " + res.result()); 11 | } else { 12 | System.out.println("Deployment failed!"); 13 | } 14 | }); 15 | ``` 16 | 17 | 如果部署成功,该完成包含部署 ID 字符串的结果传递给处理程序。 18 | 19 | 如果你想要取消部署,可以稍后使用此部署 ID。 -------------------------------------------------------------------------------- /verticles/编写Verticles.md: -------------------------------------------------------------------------------- 1 | # 编写 Verticles 2 | Verticle类必须实现[Verticle](http://vertx.io/docs/apidocs/io/vertx/core/Verticle.html)接口。 3 | 4 | 如果喜欢可以直接实现Verticle接口,但是通常简答的方法是继承抽象类[AbstractVerticle](http://vertx.io/docs/apidocs/io/vertx/core/AbstractVerticle.html) 5 | 6 | 下面是Verticles示例: 7 | 8 | ``` 9 | public class MyVerticle extends AbstractVerticle { 10 | 11 | // Called when verticle is deployed 12 | public void start() { 13 | } 14 | 15 | // Optional - called when verticle is undeployed 16 | public void stop() { 17 | } 18 | 19 | } 20 | ``` 21 | 22 | 通常你会像在上面的示例一样重写 start 方法。 23 | 24 | 当 Vert.x 部署verticle后,会调用 start 方法,当调用completed后,说明verticle启动完毕。 25 | 26 | 您也可以选择可以覆盖 stop 方法。取消部署的时候会调用。 27 | -------------------------------------------------------------------------------- /verticles/配置verticle.md: -------------------------------------------------------------------------------- 1 | # 配置verticle 2 | 在部署的时可以传递一个JSON形式的配置给verticle: 3 | 4 | ``` 5 | JsonObject config = new JsonObject().put("name", "tim").put("directory", "/blah"); 6 | DeploymentOptions options = new DeploymentOptions().setConfig(config); 7 | vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options); 8 | ``` 9 | 10 | 这种配置可通过[Context](http://vertx.io/docs/apidocs/io/vertx/core/Context.html)对象获得或直接使用config方法。 11 | 12 | 作为一个 JSON 对象返回的配置,您可以检索数据,如下所示: 13 | 14 | ``` 15 | System.out.println("Configuration: " + config().getString("name")); 16 | ``` 17 | -------------------------------------------------------------------------------- /verticles/高可用性(High Availability).md: -------------------------------------------------------------------------------- 1 | # 高可用性(High Availability) 2 | 高可用性 (HA)可以在Verticles deployed时启动,当vert.x 的实例突然死了,从集群重新部署另外的vert.x 实例。 3 | 4 | 若要启用高可用性运行verticle,只是追加`-ha`开关: 5 | 6 | ``` 7 | vertx run my-verticle.js -ha 8 | ``` 9 | 10 | 当启用高可用性,无需添加`-cluster`。 11 | 12 | 有关高可用性功能和配置的高可用性和故障转移(High Availability and Fail-Over)部分,有更多细节。 13 | -------------------------------------------------------------------------------- /不要call(调用、打电话)我们,我们会call给你。.md: -------------------------------------------------------------------------------- 1 | # 不要call(调用、打电话)我们,我们会call给你。 2 | 3 | Vert.x Api 是很大程度上由事件驱动的。这意味着,当事情发生在你感兴趣的Vert.x,Vert.x 会通过回调方式向您发送events。 4 | 5 | 一些示例events: 6 | 7 | * 计时器激活 8 | * socket收到数据 9 | * 从磁盘读取数据 10 | * 发生了异常 11 | * HTTP 服务器收到请求 12 | 13 | 通过向 Vert.x Api 提供处理程序来处理事件。例如要接收一个计时器事件每一秒你会做: 14 | 15 | ``` 16 | vertx.setPeriodic(1000, id -> { 17 | // This handler will get called every second 18 | System.out.println("timer fired!"); 19 | }); 20 | ``` 21 | 22 | 或接收到 HTTP 请求: 23 | 24 | ``` 25 | server.requestHandler(request -> { 26 | // This handler will be called every time an HTTP request is received at the server 27 | request.response().end("hello world!"); 28 | }); 29 | ``` 30 | 31 | 一段时间后当 Vert.x 有一个事件,它将传递到您的处理程序 Vert.x 将它异步调用. 32 | 33 | 这将引导我们进入Vert.x 中的一些重要概念: -------------------------------------------------------------------------------- /不要阻塞我.md: -------------------------------------------------------------------------------- 1 | # 不要阻塞我! 2 | 3 | 除了极少数例外 (一些文件系统操作的“同步”结束),没有一个 Vert.x Api 阻塞调用线程。 4 | 5 | 如果可以立即提供的结果,它将立即返回,你通常会提供一个handle来接收过一段时间的事件。 6 | 7 | 由于Vert.x API没有任何阻塞的线程,这意味着你可以使用Vert.x来处理只是使用小数目线程的大量并发。 8 | 9 | 常规阻塞API使用线程可能会阻塞: 10 | 11 | * 从socket读取数据 12 | * 向磁盘写入数据 13 | * 向收件人发送一条消息,等待答复。 14 | * … 15 | 16 | 在所有上述情况下,当您的线程正在等待结果时它不能做别的-这是实际上是浪费。 17 | 18 | 这意味着,如果你需要大量的并发使用阻塞 APIs,然后你需要大量的线程,以防止您的应用程序停止工作。 19 | 20 | 线程在他们所需要的内存(例如栈)和上下文切换方面有开销。 21 | 22 | 对于许多现代应用程序所需要的并发水平,阻塞的方法不能按比例缩放。 23 | -------------------------------------------------------------------------------- /从Vert-x开始.md: -------------------------------------------------------------------------------- 1 | # 从Vert.x开始 2 | 3 | 4 | *注意:这大部分是Java特有的-需要语言特有的调用方法* 5 | 6 | 7 | 如果没有获得[Vertx](http://vertx.io/docs/apidocs/io/vertx/core/Vertx.html)对象,Vert.x做不了什么。 8 | 9 | Vertx对象是 Vert.x 的控制中心,几乎可以做所有事,包括创建客户端和服务器,获取引用到事件总线(event bus)、 设置计时器等。 10 | 11 | 所以怎么获得Vertx实例? 12 | 13 | 如果已经嵌入了 Vert.x,然后只需创建一个实例,如下所示: 14 | 15 | ``` 16 | Vertx vertx = Vertx.vertx(); 17 | ``` 18 | 19 | 如果使用 Verticles 20 | 21 | *注意:大多数应用程序只需要一个单一的 Vert.x 实例,但如果你需要,可以创建多个 Vert.x 实例,例如,事件总线或不同的服务器和客户端之间的隔离。* 22 | 23 | #### 创建一个指定选项的Vertx 对象 24 | 25 | 创建一个 Vertx 对象时,如果默认值不是正确的选择,你还可以指定选项: 26 | 27 | ``` 28 | Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(40)); 29 | ``` 30 | 31 | [VertxOptions](http://vertx.io/docs/apidocs/io/vertx/core/VertxOptions.html)对象有许多设置,可以配置集群、 高可用性、 池的大小等。所有设置细节在Javadoc 中有描述。 32 | 33 | #### 创建群集 Vert.x 对象 34 | 35 | 如果您正在创建clustered(群集) Vert.x (更多集群相关的请参阅事件总线( event bus)),然后通常会使用异步方式创建 Vertx 对象。 36 | 37 | 这是因为不同的 Vert.x 实例在群集中组合在一起,通常需要一些时间 (也许几秒钟) 的。在这段时间,我们不想阻止调用线程,所以我们把结果以异步方式给你。 -------------------------------------------------------------------------------- /你是傻瓜吗.md: -------------------------------------------------------------------------------- 1 | # 你是傻瓜吗? 2 | 3 | 你可能注意到,在前面使用fluent API(fluent API:流API,更易使用的API,也称傻瓜式API)的例子。 4 | 5 | fluent API 是支持链式调用的。例如: 6 | 7 | ``` 8 | request.response().putHeader("Content-Type", "text/plain").write("some text").end(); 9 | ``` 10 | 11 | 整个 Vert.x Api都是这种模式,,所以要去适应它。 12 | 13 | 可以链式编写代码,当然你也可以按自己的喜欢,写上这样的代码: 14 | 15 | 16 | ``` 17 | HttpServerResponse response = request.response(); 18 | response.putHeader("Content-Type", "text/plain"); 19 | response.write("some text"); 20 | response.end(); 21 | ``` -------------------------------------------------------------------------------- /编写 HTTP 服务器和客户端.md: -------------------------------------------------------------------------------- 1 | # 编写 HTTP 服务器和客户端 2 | 3 | Vert.x 允许您轻松地编写非阻塞的 HTTP 客户端和服务器。 -------------------------------------------------------------------------------- /运行阻塞代码.md: -------------------------------------------------------------------------------- 1 | # 运行阻塞代码 2 | 3 | 在完美的世界,将没有战争或饥饿,所有 Api 将使用异步写,阳光明媚,绿色的草地有跳来跳去的兔子和手牵手的小羊羔。 4 | 5 | **但是,现实世界并不是这样。(你看过新闻最近吗?)** 6 | 7 | 事实是,大多数库,特别是在JVM的生态,Y有许多是同步API,许多的方法有可能阻塞。一个很好的例子是JDBC API - 这是本质上的同步,不管如何努力尝试,Vert.x 不能撒上魔法使之同步。 8 | 9 | 我们不打算在一夜之间把一切改写成异步,所以我们需要给你提供一个方法,一个Vert.x应用中安全地使用“传统”的阻塞API的方法。 10 | 11 | 如前所述,直接在事件循环里调用阻塞操作,会妨碍它做任何其他有用的工作。所以你怎么能这样呢? 12 | 13 | 它是通过调用`executeBlocking`指定要执行的阻塞的代码和在执行阻塞的代码时调用返回异步结果处理程序。 14 | 15 | 通过调用`executeblocking`,执行阻塞代码,当阻塞代码执行完成后通过异步回调的方式返回 16 | 17 | ``` 18 | vertx.executeBlocking(future -> { 19 | // Call some blocking API that takes a significant amount of time to return 20 | String result = someAPI.blockingMethod("hello"); 21 | future.complete(result); 22 | }, res -> { 23 | System.out.println("The result is: " + res.result()); 24 | }); 25 | ``` 26 | 27 | 默认情况下,如果 `executeBlocking` 从相同的上下文 (例如同一垂直实例) 调用几次不同的 executeBlocking 则以串行方式执行 (即一个接一个)。 28 | 29 | 默认情况下,如果`executeBlocking`在同一环境(例如同一个verticle实例)多次调用,那么不同的`executeBlocking`将串行执行(即一个接一个)。 30 | 31 | 如果不关系执行顺序,调用`executeBlocking`时可以制定`ordered`参数为`false`。在这种情况下 `executeBlocking` 会与worker pool并行执行。 32 | 33 | 34 | 运行阻塞的代码替代方法是使用[worker verticle](http://vertx.io/docs/vertx-core/java/#worker_verticles) 35 | 36 | worker verticle始终在worker池中的线程执行。 -------------------------------------------------------------------------------- /黄金法则_不要阻塞事件循环.md: -------------------------------------------------------------------------------- 1 | # 黄金法则 — 不要阻塞事件循环 2 | 3 | 我们已经知道 Vert.x Api 是非阻塞,并且不会堵塞事件循环。 4 | 如果你堵塞事件循环,那事件循环将不能做别的事,因为它被阻塞了。如果所有的event loop被阻塞了,应用程序将完全停止! 5 | 6 | 所以不要这样做!**你已经被警告**。 7 | 8 | 阻塞的例子包括: 9 | 10 | * Thread.sleep() 11 | * 等待锁 12 | * 等待互斥体或监视器 (例如同步段) 13 | * 做一个长时间的数据库操作和等待返回 14 | * 做复杂的计算,需要很长的时间。 15 | * 死循环。 16 | 17 | 如果有上述情况停止了事件循环(event loop),需要相当长的时间,你应经立即去下一步,并等待进一步的指示。 18 | 19 | 这个时间具体多长? 20 | 21 | 具体多长时间?它取决于应用程序需要的并发量。 22 | 23 | 如果你有一个单一的事件循环,并且你想要处理每秒 10000 的 http 请求,然后很明显,每个请求不能超过 0.1 ms 要处理,所以你不能阻塞比这更多的时间。 24 | 25 | **这道数学题并不是困难,作为练习留给读者。** 26 | 27 | 如果您的应用程序不响应,可能你阻塞的事件循环的地方。为了帮助您诊断此类问题,如果它检测到一段时间后事件循环还没有恢复,Vert.x会自动记录警告。如果你在日志中看到这样的警告,那么你就应该去检查应用。 28 | 29 | ``` 30 | Thread vertx-eventloop-thread-3 has been blocked for 20458 ms 31 | ``` 32 | 33 | Vert.x 还将提供`堆栈跟踪`来确定阻塞发生的位置。 34 | 35 | 如果你想关闭这些警告或更改设置,你可以在创建Vertx对象之前,使用[VertxOptions](http://vertx.io/docs/apidocs/io/vertx/core/VertxOptions.html)配置。 --------------------------------------------------------------------------------