关于在 JUnit 单元测试中如何断言某个函数的控制台输出已是我一个长久的问题. 虽然有控制台输出的函数有了副作用, 不能称之为一个纯函数, 在讲求函数式编程的今天, 纯函数是最好测试的, 所谓的 Data In, Data Out. 但总还是有这样的需求, 比如自己实现的某个日志框架的 Appender, 需要验证它向控制台的输出内容.
我先前在项目中的办法是, 先把把标准输出定向到一个
ByteArrayOutputStream中去, 完后把这个流转成字符串来断言它的内容, 最后恢复标准输出为System.out, 代码如下:ByteArrayOutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));System.out.print("Hello");
assertThat(output.toString(), is("Hello");
System.setOut(System.out);这样也能完成任务, 本质也是对的, 但稍显复杂了些. 今天读
Spring in Action一书, 发现它用了StandardOutputStreamLog这个 JUnit 的@Rule, 来自于 System Rules. 其实StandardOutputStreamLog类已不推荐使用, 取而代之的是 SystemOutRule, 所以应用SystemOutRule来断言控制台输出的测试方法就是 Read More
本文实践了如何连接 Kafka 生产和消费 Avro 序列化格式的数据, 不能像 NgAgo-gDNA 那样, 为保证实验内容及结果的可重复性, 文中所用的各中间件和组件版本如下:- Apache Kafka: kafka_2.11-0.10.0.1, 这个版本在初始始化生产者消费者的属性与之前版本有所不同.
- kafka-clients: Java API 客户端, 版本为 0.10.0.1
- Apache Avro: 1.8.1. 关于 Avro 序列化的内容可参见 Apache Avro 序列化与反序列化 (Java 实现)
- Java 8
Apache Kafka 消息系统设计为可以传输字符串, 二进制等数据, 但直接用于传输生产消费两端都能理解的对象数据会更友好. 所以我们这里用 Avro 的 Schema 来定义要传输的数据格式, 通信时采用自定义的序列化和反序列化类进行对象与字节数组间的转换.
以下是整个实验过程本地启动 Apache Kafka 服务
请参考 简单搭建 Apache Kafka 分布式消息系统 启动 ZooKeeper 和 Kafka 即可. 程序运行会自动创建相应的主题. 启动后 Kafka 开启了本地的 9092 端口, 程序中只需要连接这个端口, 不用管 ZooKeeper 的 2181 端口. Read More
像两个人交流一样要找一个互相能理解的语言, 在国内为普通话, 跑国外多用英语相通, 两个进程间通信也需要找一个大家都能理解的数据格式. 简单的如 JSON, XML, 那是自我描述性格式, XML 有 Schema 定义, 但尚无正式的 JSON Schema 规范. 在讲求效率的场合, 纯文本式的数据交换格式无法满足要求, 于是有二进制的 Google Protobuf 和 Apache Avro. 在 Apache 的生态像 Hadoop, Kafka 中自然是选用 Avro.
Avro 支持多种语言, 如 C, C++, C#, Java, PHP, Python 和 Ruby. 它使用 JSON 来定义 Schema, 通过工具可以由 Schema 生成相应语言的数据对象, 比如 Java 的 avro-tools.jar. 这样可以在跨进程跨语言透明的实现为对象交换.
本文体验 Java 环境中 Avro 数据格式的序列化与反序列化.
Avro Schema 文件就是数据生产和消费端的通信协议; 我们可以由 Schema 生成相应的 Java 对象, 然后以具体的 Java 对象交换, 或者不生成 Java 对象而纯粹以GenericRecord交互. 为操作数据的简单, 我们通常采用前一种方式, 即生成具体数据传输对象. Read More
早先都是用的基于 JMS 规范的消息系统, 像 ActiveMQ, IBM MQSeries 等. 随着互联网的发展, 大约是要适应当今大数据, 高可用性, 高效的需求, 于是诞生了 Apache Kafka 这一新时代的分布式消息系统. Apache Kafka 也是发布-订阅式的消息系统, 用 Scala 语言写的, 它最初由 LinedIn 开发并贡献到 Apache 基金会.
Kafka 的集群实质是依赖于 ZooKeeper 的集群来协同管理, 所以这里可以参照之前的 ZooKeeper 快速搭建与体验 来搭建一个 ZooKeeper 集群(其实这是一个伪集群, 实际产品中应该把 ZooKeeper 集群分布在不同的机器上).
本文主要是参考官方的 Kafka Quickstart 来快速体验 Kafka 消息系统, 下载的 Kafka 自带了 ZooKeeper, 默认只启动了一个 ZooKeeper 节点. 如需 ZooKeeper 集群可以不依赖于 Kafka 自带的 ZooKeeper 而单独搭建.
下面开始演示建立一个最简单的 Kafka 系统 Read More
Apache ZooKeeper 是一个面向分布式应用程序的高性能协调服务器, 至于它的具体介绍像能提供命名和配置管理、同步和组服务等, 请自个 Google. 虽然对 ZooKeeper 早有耳闻, 也只最近因为项目中有 Kafka 内部用到了 ZooKeeper, 所以才促使我着手去了解一下 ZooKeeper 为何物. ZooKeeper 脱胎于著名的项目 Hadoop, 它也像 Hazelcast 那样未采用严格意义的 Master-Slave 的集群方式, 而是动态选出 Leader, 这避免了单点故障的问题.
既然是集群, 实际应用是会在不同的机器上启动服务, 现如今有了 docker 很容易用它来测试多主机环境, 用docker search zookeeper就知道了. 本实例中暂不涉及 docker, 而是在同一个系统中用多个端口来启动三个 ZooKeeper 实例进行测试. 下面以 Mac/Linux 为例:下载安装 ZooKeeper
到 https://zookeeper.apache.org/releases.html#download 下载, 写下此文时的最新稳定版是 zookeeper-3.4.9.tar.gz, 下载后解压到某处, 为方便起见把解压后的 zookeeper-3.4.9/bin 加到系统环境变量 $PATH 中, 以后方便任何时候运行 zkServer.sh, zkCli.sh 这样的命令. Read More
要用到 Hazelcast 这个东西用作分布式缓存, 网上搜索了下发现这篇文章对我理解 Hazelcast 那种无主从之分, 避免了单点故障很有帮助, Hazelcast 的数据分布方式很有点像磁盘阵列 RAID 1, RAID0+1 的影子. 基本上在一个节点出现故障的情况下是不会影响数据访问的.
下面这个系列讲的很详细:- Hazelcast集群服务(1)——Hazelcast介绍
- Hazelcast集群服务(2)——Hazelcast基本配置
- Hazelcast集群服务(3)——集群功能详解
- Hazelcast集群服务(4)——分布式Map
Hazelcast 是一个开源的可嵌入式数据网格(社区版免费,企业版收费)。你可以把它看做是内存数据库,不过它与 Redis 等内存数据库又有些不同。项目地址:http://hazelcast.org/
Hazelcast 使得 Java 程序员更容易开发分布式计算系统,提供了很多 Java 接口的分布式实现,如:Map, Queue, Topic, ExecutorService, Lock, 以及 JCache 等。它以一个 JAR 包的形式提供服务,只依赖于 Java,并且提供 Java, C/C++, .NET 以及 REST 客户端,因此十分容易使用。如何存储数据
Hazelcast 服务之间是端对端的,没有主从之分,因此也不存在单点故障。集群中所有的节点都存储等量的数据以及进行等量的计算。
Hazelcast 缺省情况下把数据分为 271 个区。这个值可配置于系统属性hazelcast.partition.count。对于一个给定的键,在经过序列号、哈希并对分区总数取模之后能得到此键对应的分区号。所有的分区等量的分布与集群中所有的节点中,每个分区对应的备份也同样分布在集群中。 Read More- 我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了那么不得不说我们的思维仍然是在原地踏步, 只是本能的认为它不过是 User 实例的包装, 这与我们之前写成
1Optional<User> user = ...... 2if (user.isPresent()) { 3 return user.getOrders(); 4} else { 5 return Collections.emptyList(); 6}实质上是没有任何分别. 这就是我们将要讲到的使用好 Java 8 Optional 类型的正确姿势.1User user = ..... 2if (user != null) { 3 return user.getOrders(); 4} else { 5 return Collections.emptyList(); 6}
在里约奥运之时, 新闻一再提起五星红旗有问题, 可是我怎么看都看不出来有什么问题, 后来才道是小星星膜拜中央的姿势不对. 因此我们千万也别对自己习以为常的事情觉得理所当然, 丝毫不会觉得有何不妥, 换句话说也就是当我们切换到 Java 8 的 Optional 时, 不能继承性的对待过往 null 时的那种思维, 应该掌握好新的, 正确的使用 Java 8 Optional 的正确姿势. Read More - Java 在定义字符串的时候不支持字符串插值, 即不能在字符串中捕获作用域中的变量, 用来组成当前字符串. 而这可以说是其他各种言都具备的基本特性. 例如 Bash 中可以这样
bash-3.2$ name=Yanbin
Java 中不支持类似的方式
bash-3.2$ echo "Hello $name"
Hello YanbinString name = "Yanbin";
而使用 Java 必须用 String 的静态方法 format (注意是静态方法哦) 来间接的格式化出一个字符串, 可以这么写
String greeting = "Hello $name"; //Java 中无法把 $name 替换为 name 变量值 "Yanbin"String.format("Hello %s", "World");
我们看到在用 format 格式化时匹配参数会是一个不小的问题, 相同使用法的打印输出方法是
String.format("%1$s %1$s %s %s %2$s", "aa", 10); //aa aa aa 10 10System.out.printf(). 别说字符串插值了, 如果 format 方法是 String 的一个实例方法应用起来都会便利些, 如"Hello %s".format("World")会容易读些, Scala 的字符串实例就有format方法了. Read More - 希望 Java 能支持动态对象(匿名对象) 的特性是源于想要 Java 方法能优雅的返回多个值. 目前如果希望 Java 方法返回多个值的做法有返回一个自定义对象, 数组或列表, 或 Map. 这种需求多发生在私有方法上, 但目前的解决办法有如下弊端:
- 如果用自定义类来作为返回类型的话, 会使得类过于杂乱, 而且这些自定义类的复用性不高
- 数组或列表有太强的顺序依赖, 没有属性名告知每个位置上值的意义, 而且类型都必须为 Object
- 返回 Map 的, 在维护 Key 上容易出错(或须为 Key 定义很多字符串常量), 且类型也是为 Object.
说了上面许多, 各位可能还不定清楚我想要的是什么, 其实就是类似于 C# 的匿名对象(或曰动态对象), 看一段 C# 的方法返回一个匿名对象的例子(.NET3.5 开始引入匿名对象, .NET 4.0 后匿名对象可以作为函数值) Read More - 曾几何时在业务分层结构中的 VO 或 DTO 层充斥着无数的标准 JavaBean 类, 那些碍手脚的 getter/setter 方法简值不忍直视. 或许 JavaBean 设定规范的用意是当某些属性为只读时不提供 setter 方法, 而实际使用时, 因 getter/setter 都同时具备, 那么 JavaBean 的所有私有属性又何异于公有属性呢.
更别说对于某些形式的属性名, 若属性名为xCoordinate时, 它所对应的 getter 方法分别是getxCoordinate(),一般的 IDE 都会为它自动生成getXCoordinate()方法, 这是错误的. 实际上getXCoordinate()对应的属性名是XCoordinate.
所以 Play Framework 1 以及 Play Framework 2.4.6 之前的版本采用了字节码增强的技术, 实现了像 Objective-C 的 @property 的特性, 即只要声明公有属性, 编译器为该属性生成默认的 getter/setter 方法, 您也可以手工去覆盖个别默认的 getter/setter 方法.
因此在 Play Framework 中书写的的 model 类就只需要属性了, 像1public class User { 2 public int id; 3 public String name; 4 public String email; 5 public String address; 6}
就这么简单, 想像一下如果我们为一个众多属性的 model 类补全所有的 getter/setter 方法读起来有多恐怖. Read More