Akka-http的客户端连接模式除Connection-Level和Host-Level之外还有一种非常便利的模式:Request-Level-Api。这种模式免除了连接Connection的概念,任何时候可以直接调用singleRequest来与服务端沟通。下面我们用几个例子来示范singleRequest的用法:

  1. (for {
  2. response <- Http().singleRequest(HttpRequest(method=HttpMethods.GET,uri="http://localhost:8011/message"))
  3. message <- Unmarshal(response.entity).to[String]
  4. } yield message).andThen {
  5. case Success(msg) => println(s"Received message: $msg")
  6. case Failure(err) => println(s"Error: ${err.getMessage}")
  7. }.andThen {case _ => sys.terminate()}

这是一个GET操作:用Http().singleRequest直接把HttpRequest发送给服务端uri并获取返回的HttpResponse。我们看到,整组函数的返回类型都是Future[?],所以用for-comprehension来把所有实际运算包嵌在Future运算模式内(context)。下面这个例子是客户端上传数据示范:

  1. (for {
  2. entity <- Marshal("Wata hell you doing?").to[RequestEntity]
  3. response <- Http().singleRequest(HttpRequest(method=HttpMethods.PUT,uri="http://localhost:8011/message",entity=entity))
  4. message <- Unmarshal(response.entity).to[String]
  5. } yield message).andThen {
  6. case Success(msg) => println(s"Received message: $msg")
  7. case Failure(err) => println(s"Error: ${err.getMessage}")
  8. }.andThen {case _ => sys.terminate()}

以上是个PUT操作。我们需要先构建数据载体HttpEntity。格式转换函数Marshal也返回Future[HttpEntity],所以也可以包含在for语句内。关注一下这个andThen,它可以连接一串多个monadic运算,在不影响上游运算结果的情况下实现一些副作用计算。值得注意的是上面这两个例子虽然表现形式很简洁,但我们无法对数据转换过程中的异常及response的状态码等进行监控。所以我们应该把整个过程拆分成两部分:先获取response,再具体处理response,包括核对状态,处理数据等:

  1. case class Item(id: Int, name: String, price: Double)
  2.  
  3. def getItem(itemId: Int): Future[HttpResponse] = for {
  4. response <- Http().singleRequest(HttpRequest(method=HttpMethods.GET,uri = s"http://localhost:8011/item/$itemId"))
  5. } yield response
  6.  
  7. def extractEntity[T](futResp: Future[HttpResponse])(implicit um: Unmarshaller[ResponseEntity,T]) = {
  8. futResp.andThen {
  9. case Success(HttpResponse(StatusCodes.OK, _, entity, _)) =>
  10. Unmarshal(entity).to[T]
  11. .onComplete {
  12. case Success(t) => println(s"Got response entity: ${t}")
  13. case Failure(e) => println(s"Unmarshalling failed: ${e.getMessage}")
  14. }
  15. case Success(_) => println("Exception in response!")
  16. case Failure(err) => println(s"Response Failed: ${err.getMessage}")
  17. }
  18. }
  19. extractEntity[Item](getItem())

现在这个extractEntity[Item](getItem(13))可以实现全过程的监控管理了。用同样的模式实现PUT操作:

  1. def putItem(item: Item): Future[HttpResponse] =
  2. for {
  3. reqEntity <- Marshal(item).to[RequestEntity]
  4. response <- Http().singleRequest(HttpRequest(method=HttpMethods.PUT,uri="http://localhost:8011/item",entity=reqEntity))
  5. } yield response
  6.  
  7. extractEntity[Item](putItem(Item(,"Item#23", 46.0)))
  8. .andThen { case _ => sys.terminate()}

当然,我们还是使用了前面几篇讨论里的Marshalling方式来进行数据格式的自动转换:

  1. import de.heikoseeberger.akkahttpjson4s.Json4sSupport
  2. import org.json4s.jackson
  3. ...
  4. trait JsonCodec extends Json4sSupport {
  5. import org.json4s.DefaultFormats
  6. import org.json4s.ext.JodaTimeSerializers
  7. implicit val serilizer = jackson.Serialization
  8. implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
  9. }
  10. object JsConverters extends JsonCodec
  11. ...
  12. import JsConverters._
  13.  
  14. implicit val jsonStreamingSupport = EntityStreamingSupport.json()
  15. .withParallelMarshalling(parallelism = , unordered = false)

如果我们需要对数据交换过程进行更细致的管控,用Host-Level-Api会更加适合。下面我们就针对Host-Level-Api构建一个客户端的工具库:

  1. class PooledClient(host: String, port: Int, poolSettings: ConnectionPoolSettings)
  2. (implicit sys: ActorSystem, mat: ActorMaterializer) {
  3.  
  4. import sys.dispatcher
  5.  
  6. private val cnnPool: Flow[(HttpRequest, Int), (Try[HttpResponse], Int), Http.HostConnectionPool] =
  7. Http().cachedHostConnectionPool[Int](host = host, port = port, settings = poolSettings)
  8. //单一request
  9. def requestSingleResponse(req: HttpRequest): Future[HttpResponse] = {
  10. Source.single(req -> )
  11. .via(cnnPool)
  12. .runWith(Sink.head).flatMap {
  13. case (Success(resp), _) => Future.successful(resp)
  14. case (Failure(fail), _) => Future.failed(fail)
  15. }
  16. }
  17. //组串request
  18. def orderedResponses(reqs: Iterable[HttpRequest]): Future[Iterable[HttpResponse]] = {
  19. Source(reqs.zipWithIndex.toMap)
  20. .via(cnnPool)
  21. .runFold(SortedMap[Int, Future[HttpResponse]]()) {
  22. case (m, (Success(r), idx)) => m + (idx -> Future.successful(r))
  23. case (m, (Failure(f), idx)) => m + (idx -> Future.failed(f))
  24. }.flatMap { m => Future.sequence(m.values) }
  25. }
  26. }

下面是一种比较安全的模式:使用了queue来暂存request从而解决因发送方与接收方速率不同所产生的问题:

  1. class QueuedRequestsClient(host: String, port: Int, poolSettings: ConnectionPoolSettings)
  2. (qsize: Int = , overflowStrategy: OverflowStrategy = OverflowStrategy.dropNew)
  3. (implicit sys: ActorSystem, mat: ActorMaterializer) {
  4. import sys.dispatcher
  5. private val cnnPool: Flow[(HttpRequest,Promise[HttpResponse]),(Try[HttpResponse],Promise[HttpResponse]),Http.HostConnectionPool] =
  6. Http().cachedHostConnectionPool[Promise[HttpResponse]](host=host,port=port,settings=poolSettings)
  7.  
  8. val queue =
  9. Source.queue[(HttpRequest, Promise[HttpResponse])](qsize, overflowStrategy)
  10. .via(cnnPool)
  11. .to(Sink.foreach({
  12. case ((Success(resp), p)) => p.success(resp)
  13. case ((Failure(e), p)) => p.failure(e)
  14. })).run()
  15.  
  16. def queueRequest(request: HttpRequest): Future[HttpResponse] = {
  17. val responsePromise = Promise[HttpResponse]()
  18. queue.offer(request -> responsePromise).flatMap {
  19. case QueueOfferResult.Enqueued => responsePromise.future
  20. case QueueOfferResult.Dropped => Future.failed(new RuntimeException("Queue overflowed. Try again later."))
  21. case QueueOfferResult.Failure(ex) => Future.failed(ex)
  22. case QueueOfferResult.QueueClosed => Future.failed(new RuntimeException("Queue was closed (pool shut down) while running the request. Try again later."))
  23. }
  24. }
  25. }

下面是这些工具函数的具体使用示范:

  1. val settings = ConnectionPoolSettings(sys)
  2. .withMaxConnections()
  3. .withMaxOpenRequests()
  4. .withMaxRetries()
  5. .withPipeliningLimit()
  6. val pooledClient = new PooledClient("localhost",,settings)
  7.  
  8. def getItemByPool(itemId: Int): Future[HttpResponse] = for {
  9. response <- pooledClient.requestSingleResponse(HttpRequest(method=HttpMethods.GET,uri = s"http://localhost:8011/item/$itemId"))
  10. } yield response
  11.  
  12. extractEntity[Item](getItemByPool())
  13.  
  14. def getItemsByPool(itemIds: List[Int]): Future[Iterable[HttpResponse]] = {
  15. val reqs = itemIds.map { id =>
  16. HttpRequest(method = HttpMethods.GET, uri = s"http://localhost:8011/item/$id")
  17. }
  18. val rets = (for {
  19. responses <- pooledClient.orderedResponses(reqs)
  20. } yield responses)
  21. rets
  22. }
  23. val futResps = getItemsByPool(List(,,))
  24.  
  25. futResps.andThen {
  26. case Success(listOfResps) => {
  27. listOfResps.foreach { r =>
  28. r match {
  29. case HttpResponse(StatusCodes.OK, _, entity, _) =>
  30. Unmarshal(entity).to[Item]
  31. .onComplete {
  32. case Success(t) => println(s"Got response entity: ${t}")
  33. case Failure(e) => println(s"Unmarshalling failed: ${e.getMessage}")
  34. }
  35. case _ => println("Exception in response!")
  36. }
  37. }
  38. }
  39. case _ => println("Failed to get list of responses!")
  40. }
  41.  
  42. val queuedClient = new QueuedRequestsClient("localhost",,settings)()
  43.  
  44. def putItemByQueue(item: Item): Future[HttpResponse] =
  45. for {
  46. reqEntity <- Marshal(item).to[RequestEntity]
  47. response <- queuedClient.queueRequest(HttpRequest(method=HttpMethods.PUT,uri="http://localhost:8011/item",entity=reqEntity))
  48. } yield response
  49.  
  50. extractEntity[Item](putItemByQueue(Item(,"Item#23", 46.0)))
  51. .andThen { case _ => sys.terminate()}

下面是本次讨论的示范源代码:

服务端代码:

  1. import akka.actor._
  2. import akka.stream._
  3. import akka.http.scaladsl.Http
  4. import akka.http.scaladsl.server.Directives._
  5.  
  6. import de.heikoseeberger.akkahttpjson4s.Json4sSupport
  7. import org.json4s.jackson
  8. trait JsonCodec extends Json4sSupport {
  9. import org.json4s.DefaultFormats
  10. import org.json4s.ext.JodaTimeSerializers
  11. implicit val serilizer = jackson.Serialization
  12. implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
  13. }
  14. object JsConverters extends JsonCodec
  15.  
  16. object TestServer extends App with JsonCodec {
  17. implicit val httpSys = ActorSystem("httpSystem")
  18. implicit val httpMat = ActorMaterializer()
  19. implicit val httpEC = httpSys.dispatcher
  20.  
  21. import JsConverters._
  22.  
  23. case class Item(id: Int, name: String, price: Double)
  24. val messages = path("message") {
  25. get {
  26. complete("hello, how are you?")
  27. } ~
  28. put {
  29. entity(as[String]) {msg =>
  30. complete(msg)
  31. }
  32. }
  33. }
  34. val items =
  35. (path("item" / IntNumber) & get) { id =>
  36. get {
  37. complete(Item(id, s"item#$id", id * 2.0))
  38. }
  39. } ~
  40. (path("item") & put) {
  41. entity(as[Item]) {item =>
  42. complete(item)
  43. }
  44. }
  45.  
  46. val route = messages ~ items
  47.  
  48. val (host, port) = ("localhost", )
  49.  
  50. val bindingFuture = Http().bindAndHandle(route,host,port)
  51.  
  52. println(s"Server running at $host $port. Press any key to exit ...")
  53.  
  54. scala.io.StdIn.readLine()
  55.  
  56. bindingFuture.flatMap(_.unbind())
  57. .onComplete(_ => httpSys.terminate())
  58.  
  59. }

客户端源代码:

  1. import akka.actor._
  2. import akka.http.scaladsl.settings.ConnectionPoolSettings
  3. import akka.stream._
  4. import akka.stream.scaladsl._
  5. import akka.http.scaladsl.Http
  6. import akka.http.scaladsl.model._
  7.  
  8. import scala.util._
  9. import de.heikoseeberger.akkahttpjson4s.Json4sSupport
  10. import org.json4s.jackson
  11.  
  12. import scala.concurrent._
  13. import akka.http.scaladsl.unmarshalling.Unmarshal
  14. import akka.http.scaladsl.unmarshalling._
  15. import akka.http.scaladsl.marshalling.Marshal
  16.  
  17. import scala.collection.SortedMap
  18. import akka.http.scaladsl.common._
  19.  
  20. trait JsonCodec extends Json4sSupport {
  21. import org.json4s.DefaultFormats
  22. import org.json4s.ext.JodaTimeSerializers
  23. implicit val serilizer = jackson.Serialization
  24. implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
  25. }
  26. object JsConverters extends JsonCodec
  27.  
  28. class PooledClient(host: String, port: Int, poolSettings: ConnectionPoolSettings)
  29. (implicit sys: ActorSystem, mat: ActorMaterializer) {
  30.  
  31. import sys.dispatcher
  32.  
  33. private val cnnPool: Flow[(HttpRequest, Int), (Try[HttpResponse], Int), Http.HostConnectionPool] =
  34. Http().cachedHostConnectionPool[Int](host = host, port = port, settings = poolSettings)
  35.  
  36. def requestSingleResponse(req: HttpRequest): Future[HttpResponse] = {
  37. Source.single(req -> )
  38. .via(cnnPool)
  39. .runWith(Sink.head).flatMap {
  40. case (Success(resp), _) => Future.successful(resp)
  41. case (Failure(fail), _) => Future.failed(fail)
  42. }
  43. }
  44.  
  45. def orderedResponses(reqs: Iterable[HttpRequest]): Future[Iterable[HttpResponse]] = {
  46. Source(reqs.zipWithIndex.toMap)
  47. .via(cnnPool)
  48. .runFold(SortedMap[Int, Future[HttpResponse]]()) {
  49. case (m, (Success(r), idx)) => m + (idx -> Future.successful(r))
  50. case (m, (Failure(f), idx)) => m + (idx -> Future.failed(f))
  51. }.flatMap { m => Future.sequence(m.values) }
  52. }
  53. }
  54. class QueuedRequestsClient(host: String, port: Int, poolSettings: ConnectionPoolSettings)
  55. (qsize: Int = , overflowStrategy: OverflowStrategy = OverflowStrategy.dropNew)
  56. (implicit sys: ActorSystem, mat: ActorMaterializer) {
  57. import sys.dispatcher
  58. private val cnnPool: Flow[(HttpRequest,Promise[HttpResponse]),(Try[HttpResponse],Promise[HttpResponse]),Http.HostConnectionPool] =
  59. Http().cachedHostConnectionPool[Promise[HttpResponse]](host=host,port=port,settings=poolSettings)
  60.  
  61. val queue =
  62. Source.queue[(HttpRequest, Promise[HttpResponse])](qsize, overflowStrategy)
  63. .via(cnnPool)
  64. .to(Sink.foreach({
  65. case ((Success(resp), p)) => p.success(resp)
  66. case ((Failure(e), p)) => p.failure(e)
  67. })).run()
  68.  
  69. def queueRequest(request: HttpRequest): Future[HttpResponse] = {
  70. val responsePromise = Promise[HttpResponse]()
  71. queue.offer(request -> responsePromise).flatMap {
  72. case QueueOfferResult.Enqueued => responsePromise.future
  73. case QueueOfferResult.Dropped => Future.failed(new RuntimeException("Queue overflowed. Try again later."))
  74. case QueueOfferResult.Failure(ex) => Future.failed(ex)
  75. case QueueOfferResult.QueueClosed => Future.failed(new RuntimeException("Queue was closed (pool shut down) while running the request. Try again later."))
  76. }
  77. }
  78. }
  79. object ClientRequesting extends App {
  80. import JsConverters._
  81.  
  82. implicit val sys = ActorSystem("sysClient")
  83. implicit val mat = ActorMaterializer()
  84. implicit val ec = sys.dispatcher
  85.  
  86. implicit val jsonStreamingSupport = EntityStreamingSupport.json()
  87. .withParallelMarshalling(parallelism = , unordered = false)
  88.  
  89. case class Item(id: Int, name: String, price: Double)
  90.  
  91. def extractEntity[T](futResp: Future[HttpResponse])(implicit um: Unmarshaller[ResponseEntity,T]) = {
  92. futResp.andThen {
  93. case Success(HttpResponse(StatusCodes.OK, _, entity, _)) =>
  94. Unmarshal(entity).to[T]
  95. .onComplete {
  96. case Success(t) => println(s"Got response entity: ${t}")
  97. case Failure(e) => println(s"Unmarshalling failed: ${e.getMessage}")
  98. }
  99. case Success(_) => println("Exception in response!")
  100. case Failure(err) => println(s"Response Failed: ${err.getMessage}")
  101. }
  102. }
  103.  
  104. (for {
  105. response <- Http().singleRequest(HttpRequest(method=HttpMethods.GET,uri="http://localhost:8011/message"))
  106. message <- Unmarshal(response.entity).to[String]
  107. } yield message).andThen {
  108. case Success(msg) => println(s"Received message: $msg")
  109. case Failure(err) => println(s"Error: ${err.getMessage}")
  110. } //.andThen {case _ => sys.terminate()}
  111.  
  112. (for {
  113. entity <- Marshal("Wata hell you doing?").to[RequestEntity]
  114. response <- Http().singleRequest(HttpRequest(method=HttpMethods.PUT,uri="http://localhost:8011/message",entity=entity))
  115. message <- Unmarshal(response.entity).to[String]
  116. } yield message).andThen {
  117. case Success(msg) => println(s"Received message: $msg")
  118. case Failure(err) => println(s"Error: ${err.getMessage}")
  119. } //.andThen {case _ => sys.terminate()}
  120.  
  121. def getItem(itemId: Int): Future[HttpResponse] = for {
  122. response <- Http().singleRequest(HttpRequest(method=HttpMethods.GET,uri = s"http://localhost:8011/item/$itemId"))
  123. } yield response
  124.  
  125. extractEntity[Item](getItem())
  126.  
  127. def putItem(item: Item): Future[HttpResponse] =
  128. for {
  129. reqEntity <- Marshal(item).to[RequestEntity]
  130. response <- Http().singleRequest(HttpRequest(method=HttpMethods.PUT,uri="http://localhost:8011/item",entity=reqEntity))
  131. } yield response
  132.  
  133. extractEntity[Item](putItem(Item(,"Item#23", 46.0)))
  134. .andThen { case _ => sys.terminate()}
  135.  
  136. val settings = ConnectionPoolSettings(sys)
  137. .withMaxConnections()
  138. .withMaxOpenRequests()
  139. .withMaxRetries()
  140. .withPipeliningLimit()
  141. val pooledClient = new PooledClient("localhost",,settings)
  142.  
  143. def getItemByPool(itemId: Int): Future[HttpResponse] = for {
  144. response <- pooledClient.requestSingleResponse(HttpRequest(method=HttpMethods.GET,uri = s"http://localhost:8011/item/$itemId"))
  145. } yield response
  146.  
  147. extractEntity[Item](getItemByPool())
  148.  
  149. def getItemsByPool(itemIds: List[Int]): Future[Iterable[HttpResponse]] = {
  150. val reqs = itemIds.map { id =>
  151. HttpRequest(method = HttpMethods.GET, uri = s"http://localhost:8011/item/$id")
  152. }
  153. val rets = (for {
  154. responses <- pooledClient.orderedResponses(reqs)
  155. } yield responses)
  156. rets
  157. }
  158. val futResps = getItemsByPool(List(,,))
  159.  
  160. futResps.andThen {
  161. case Success(listOfResps) => {
  162. listOfResps.foreach { r =>
  163. r match {
  164. case HttpResponse(StatusCodes.OK, _, entity, _) =>
  165. Unmarshal(entity).to[Item]
  166. .onComplete {
  167. case Success(t) => println(s"Got response entity: ${t}")
  168. case Failure(e) => println(s"Unmarshalling failed: ${e.getMessage}")
  169. }
  170. case _ => println("Exception in response!")
  171. }
  172. }
  173. }
  174. case _ => println("Failed to get list of responses!")
  175. }
  176.  
  177. val queuedClient = new QueuedRequestsClient("localhost",,settings)()
  178.  
  179. def putItemByQueue(item: Item): Future[HttpResponse] =
  180. for {
  181. reqEntity <- Marshal(item).to[RequestEntity]
  182. response <- queuedClient.queueRequest(HttpRequest(method=HttpMethods.PUT,uri="http://localhost:8011/item",entity=reqEntity))
  183. } yield response
  184.  
  185. extractEntity[Item](putItemByQueue(Item(,"Item#23", 46.0)))
  186. .andThen { case _ => sys.terminate()}
  187.  
  188. }

Akka(37): Http:客户端操作模式的更多相关文章

  1. HDFS的Java客户端操作代码(HDFS的查看、创建)

    1.HDFS的put上传文件操作的java代码: package Hdfs; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  2. arm9的操作模式,寄存器,寻址方式

    工作模式 Arm有7种工作模式: 名称 简称 简介 User Usr 正常用户程序执行的模式(linux下用户程序就是在这一模式执行的.) FIQ Fiq 快速中断模式 IRQ Irq 普通中断模式 ...

  3. IdentityServer4 (1) 客户端授权模式(Client Credentials)

    写在前面 1.源码(.Net Core 2.2) git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git 2.相关章节 2.1. ...

  4. PYTHON工业互联网应用实战12—客户端操作

    本章节我们将实现与admin里类似的列操作"下达"功能,演示客户端是如何实现操作功能,同时,演示也会强调一点,何时合并你的功能代码,避免相同功能使用不同的代码段来实现,在企业开发中 ...

  5. ListView多选操作模式——上下文操作模式

    1.什么叫上下文操作模式 2.如何进入上下文操作模式 1.ListView自身带了单选.多选模式,可通过listview.setChoiceMode来设置: listview.setChoiceMod ...

  6. java web 获取客户端操作系统信息

    package com.java.basic.pattern; import java.util.regex.Matcher; import java.util.regex.Pattern; /** ...

  7. Hadoop系列007-HDFS客户端操作

    title: Hadoop系列007-HDFS客户端操作 date: 2018-12-6 15:52:55 updated: 2018-12-6 15:52:55 categories: Hadoop ...

  8. pytthon—day8 读写模式的结合、文件操作模式、with完成文本文件复制、游标操作

    一.读写模式的结合 w:写指没有新建文件,有文件就清空 w=open('1.txt','w',encoding='utf-8') w.write('000\n') 在写入数据时,需要及时处理内存空间, ...

  9. 使用Java客户端操作elasticsearch(二)

    承接上文,使用Java客户端操作elasticsearch,本文主要介绍 常见的配置 和Sniffer(集群探测) 的使用. 常见的配置 前面已介绍过,RestClientBuilder支持同时提供一 ...

随机推荐

  1. JavaScript面向对象(OOP)

      前  言 JRedu 面向对象程序设计(简称OOP)是现在最流行的程序设计方法,这种方法有别于基于过程的程序设计方法.在写面向对象的WEB应用程序方面JavaScript是一种很好的选择.它能支持 ...

  2. Opencv处理鼠标事件-OpenCV步步精深

    在图片上双击过的位置绘制一个 圆圈 鼠标事件就是和鼠标有关的,比如左键按下,左键松开,右键按下,右键松开,双击右键等等. 我们可以通过鼠标事件获得与鼠标对应的图片上的坐标.我们通过以下函数来调用查看所 ...

  3. linux_base_commond_one

    1.cd commond a. cd usr 切换到该目录下usr目录  b. cd ../ 切换到上一层目录  c.cd / 切换到系统根目录  d. cd ~ 切换到用户主目录 e. cd - 切 ...

  4. 阿里巴巴Java规约插件试用

    阿里Java开发规约Eclipse插件介绍 阿里巴巴集团配合<阿里巴巴Java开发手册>PDF终极版开发的IDE插件,目前包括IDEA插件.Eclipse插件. 安装 检查环境 插件要求: ...

  5. win10 uwp json

    本文讲的是关于在uwp使用json的简单使用,json应用很多,因为我只是写简单使用,说的东西可能不对或者不符合每个人的预期.如果觉得我有讲的不对的,就多多包含,或者直接关掉这篇文章,但是请勿生气或者 ...

  6. Java IO(IO流)-1

    IO流 第一部分 (outputStream/InputStream Writer/Redaer) IO流对象中输入和输出是相辅相成的,输出什么,就可以输入什么. IO的命名方式为前半部分能干什么,后 ...

  7. Amaze UI 是一个移动优先的跨屏前端框架。 http://amazeui.org/

    http://amazeui.org/ Amaze UI 是一个移动优先的跨屏前端框架.... Amaze UI 以移动优先(Mobile first)为理念,从小屏逐步扩展到大屏,最终实现所有屏幕适 ...

  8. 浅析Java源码之LinkedList

    可以骂人吗???辛辛苦苦写了2个多小时搞到凌晨2点,点击保存草稿退回到了登录页面???登录成功草稿没了???喵喵喵???智障!!气! 很厉害,隔了30分钟,我的登录又失效了,草稿再次回滚,不客气了,* ...

  9. chromium源码阅读--进程间通信(IPC)

    第一篇就有提到Chromium是目前默认是采用多进程架构,当然,chromium有singe-process的版本. 多进程与多线程的区别,确实有很多可以讲的,我的另一篇博客也讲了一些,这里是从浏览器 ...

  10. Uncle Tom's Inherited Land*

    Uncle Tom's Inherited Land* Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...