以实际 Java 项目中的单元测试 Mock 框架基本是 Mockito 2 了,因为它有一个十分流畅的 API。Mockito 2也为 JUnit 5 配上了 MockitoExtension, 所以 JUnit 5 下使用 Mockito 2 的关节也打通了。但在我们享受 Mockito 2 便利的同时,与 JMockit 相比局限性就很明显,因为 Mockito 2 是通过创建匿名子类来进行 Mock 的,所以任何子类对父类无法突破的方面它都存在。譬如,final 类, final 方法, 私有方法, 静态方法, 构造函数都是无法通过子类型进行重写的。所以除非特别需要,在 Mockito 2 无法胜任时都求助于 JMockit,JMockit 借助于 javaagent 取得了 JVM 的高控制权才得已为所欲为。
当 Mockito 来到了 2.1.0 版本,它也觉得不能对以上所有的限制置若罔闻, 首先带给我们的突破是它也可以 Mock final 类和 final 方法,虽然仍处于孵化器中,但毕竟是应用在单元测试中,能用就很不错了,只要以后不被拿走就行。这是官方对它的介绍 Mock the unmockable: opt-in mocking of final classes/methods
下面我亲自操作一遍,并给出更全方位的测试样例 Read More
JUnit 5 刚出来那时,也就是第一个版本 5.0.0 时,还不能很好的支持 Mockito 的测试,因为 Mockito 没能跟得那么紧密。那时候 JUnit 5 只能试验性的提供了一个极不正式的 com.example.mockito.MockitoExtension, 看那包名就知道不是来真的,所以决定再等。JUnit 5 不再原生支持 JUnit 4 的 Rule,一切都将是 Extension,那也是要求 Mockito 能够与之俱进。现在等来了,JUnit 5 进化到了 5.2.0, Mockito 也早已有了一个单独的模块mockito-junit-jupiter来迎接它。
在 Mockito 2.1.0 的 What's new in Mockito 2 中记述了 JUnit 5 为 Mockito 2 开发了一个 MockitoExtension。追溯到 Mockito 2 的 Release Notes, 我们发现 Mockito 2 官方最早引入 MockitoExtension 的版本是 2.16.3(2018-03023)。我对 Mockito 对 JUnit 5 支持的最新更新是从这个 Pull Request MockitoExtension for JUnit5 得知的。
一句话讲就是现在的 Mockito 2 有原生态的 MockitoExtension 来支援 JUnit 5, 可以非常放心可靠的让 JUnit 5 和 Mockito 2 一起稳定工作。因此前面那个包名带example字样的 MockitoExtension 链接也就无效了。 Read More
当我们把数据搬上云端,为了保护敏感数据一定要对数据存储进行加密。而对于 S3 上的数据加密最简单莫过于启用服务端数据加密,可以是 AES-256 或 AWS-KMS。进行了服务端加密码的文件有什么不同呢?首先从 AWS S3 文件列表视图中看到的文件大小与原始文件大小是一样的,其实数据在 AWS 机房是加密存储了的,比如说直接在 AWS 服务器上拷出那些 S3 文件是不能理解的。
本文涉及的内容包括:- 服务器端加密后的 S3 文件有何不同
- 不启用 Bucket 的默认加密如何进行服务端数据加密(含 AWS CLI 和 Java 代码操作)
- 启用及应用 Bucket 的默认加密
- 上传与下载文件的 IAM role 需要的权限
服务器端加密后的 S3 文件有何不同
首先看现象,后面才能确认我们的操作是否对数据真的进行了服务端加密。查看使用 AWS-KMS key 加密后的 S3 文件的Overview, 看到下面两个属性Server-side encryption
没加密的话, Server-side encryption 是 None, 并且没有 KMS key ID 属性。 Read More
AWS-KMS KMS key ID
arn:aws:kms:us-east-1:123456789012:key/e4ce859b-786b-4b8e-8b73-4968adb6e4ed
在命名本文的标题都敲打了几分钟时间,问题很简单,然而用简短的一个标题完全描述出来却有点费事。在 Spring MVC 项目结合 Springfox 来生成 Swagger API 文档时,如果一个资源操作因为请求参数的不同而映射到多个 controller 方法,那么 Swagger 可能只能生成某一个 API 条目,其余都被忽略。至于为什么说是 "可能", 可能正好未遵循命名规范而躲过了这一劫。由此引出我们的问题
我们这里用了资源操作一词,它包含了两部分信息: 资源与操作,比如/users/{userId}是资源,而发生在其上的 HTTP 各种方法,如 POST, GET, PUT, DELETE 等就是操作。而 Spring MVC 中允许我们针对不同的查询参数把相同的资源操作映射到不同的 controller 方法上,也是为了保持逻辑上更为清晰。
比如下面的例子路由配置的例子GET /users/{userId} UserController.getUserInfo //默认
看到上面资源与操作完全相同,仅仅因为 source 查询参数的不同而映射到三个 controller 方法。用代码体现如下图 Read More
GET /users/{userId} UserController.getUserInfo //当有 ?source=file 时
GET /users/{userId} CloudUserController.getUserInfoFromCloud //当有 ?source=cloud 时
这是一个最基本的 Spring 4 MVC 的 Maven 项目,非 SpringBoot 的,SpringBoot 由于有许多自动化配置特性,会更简单些。本例全部用 Java 代码作为配置,免除了创建web.xml和如dispatcher-servlet.xml这样的文件。本人更倾向于 Java 配置,它的优势在于能进行编译期检查,逻辑性也强,配置文件只是改动无需重新编译,都是要重启服务的; 关于使用 XML 配置文件的方式可参考文后的链接。
本文侧重于 Spring MVC 项目提供 RESTful JSON API, 因而静态 Web 内容提及较少。创建一个 Maven 项目的方式,可以直接创建一个pom.xml文件,然后编辑它的内容,使用 IntelliJ IDEA 的话只需要选择导入为一个 Maven 项目就成,Eclipse 的话可能还要事先运行mvn eclipse:eclipse初始化一下。项目结构布局
就是一个普通的 Maven 项目,稍稍不同的是 src/main 目录中除了 java 和 resources 之外,还有 webapp 目录,用于存放 web 静态文件或模板文件的。
Read More
AWS Batch 提供了简单有效的方式来运行 Docker 镜像,在单纯执行一个计算任务时比 ECS 使用起来要方便许多。AWS Batch 在提交任务时可以执行command,environment和parameters, 那么它将如何传递那些参数给 Docker 容器呢?
首先看一下提交任务的脚本1aws batch submit-job \ 2 --job-name test-job \ 3 --job-queue test-job-queue \ 4 --job-definition test-job-definition \ 5 --container-overrides='command=echo,hello,environment=[{name=JAVA_OPTS,value=-Xmx4G}]'
注:aws cli 命令参数中有-时需要用 --parameters='--name=Spring' 等号的格式
我们将用上面的脚本提交一个任务,然后用docker inspect <container-id>观察 Docker 容器收到了什么参数
也没什么意外的,inspect 容器后我们看到 Read More
我们在运行 docker 镜像时希望能用下面的命令向容器传递命令行参数docker run <image-name> <command> arg1 arg2
其实只有第一种形式,紧随镜像名后那个总是一个命令,其后才是参数。如果要向 docker 容器传递参数时,Dockerfile 该如何写,这就有必要稍稍了解一下 Dockerfile 中 CMD 和 ENTRYPOINT 这两个指令,并且它们有 exec 和 shell 两种格式的写法。详情请见上篇 Dockerfile 中命令的两种书写方式的区别。
docker run <image-name> arg1 arg2
对于一个 docker 镜像,我们可以这么来理解 ENTRYPOINT 与 CMD 的关系- 如果没有定义 ENTRYPOINT, CMD 将作为它的 ENTRYPOINT
- 定义了 ENTRYPOINT 的话,CMD 只为 ENTRYPOINT 提供参数
- CMD 可由
docker run <image>后的命令覆盖,同时覆盖参数
对于 #1 和 #2 更精致的理解是容器运行的最终入口由 ENTRYPOINT 和实际的 CMD 拼接而成。ENTRYPOINT 和 CMD 需转换为实际镜像中的 exec 格式来拼接,合并后的第一个元素是命令,其余是它的参数。 Read More
最早的初衷是要研究一下运行 Docker 容器时如何向其传递参数,却冷不防掉入了另一个深渊,不得不关心起 Dockerfile 中命令(包括 RUN, CMD 和 ENTRYPOINT) 的两种不同写法上的区别。
所以呢,先要稍稍了解一下 Dockerfile 中 RUN, CMD, ENTRYPOINT 这三个指令- RUN 执行命令并创建新的镜像层,常用于安装软件包。可以多个,为避免创建过多的镜像层,我们尽量把命令合在一起,用分号或 &&。它与容器运行期无关。
- CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够在启动容器时被覆盖。多个 CMD 只有最后一个是有效的
- ENTRYPOINT 配置容器启动时运行的命令。多个 ENTRYPOINT 也是只有最后一个有效
关于以上三个命令的区别,这儿有篇文章讲得很清楚 RUN vs CMD vs ENTRYPOINT - 每天5分钟玩转 Docker 容器技术(17),此处也照搬了些文字。
RUN, CMD 和 ENTRYPOINT 都支持两种写法,即 exec 和 shell 格式,见 Dockerfile reference #ENTRYPOINT 对这两种方式的解释。RUN 只影响如何构建镜像,所以镜像中不保留 RUN 命令。CMD 和 ENTRYPOINT 都可以在运行容器时执行命令,这里不讲述它们间的区别,而要说的是它们所支持的 exec 和 shell 两种格式的写法。此篇以 ENTRYPOINT 为例说明两种格式的区别,CMD 类似。 Read More
和 Lambda 类似,AWS 的 SQS 队列也提供了 DLQ(Dead Letter Queue) 来支持重试功能,可以设定某一个消息在接收多次重新变得可见后进入到另一个 SQS 队列中。比如说队列 user-id-queue,设定了它的 Redrive Policy 为三次接收后转入到另一个 SQS 队列 user-id-dlq, 就会显示为Maximum Receives 3
Dead Letter Queue arn:aws:sqs:us-east-1:<account_id>:user-id-dlq在运用 SQS 的 DLQ 之前首先要理解 SQS 中消息的几个概念- Message Available: SQS 客户端可以获取到的消息, 即 Visible Messages
- Messages in Flight: 消息被 SQS 收取了之后,由 Available 转为 In Flight, 该状态的消息不能被客户端接收到
- Visibility Timeout: 消息停留在 In Flight 状态的时间, 如果在 Timeout 之前未删除这个消息,该消息重新变为 Available 状态
我们可以设置 SQS 队列的默认 Visibility Timeout 大小,也可以在代码中收取消息时指定这个值。
所以我们能够在集群环境中应用 SQS 的这个特性让多个节点同时监听单个 SQS 队列,基本上保证每个节点处理各自不同的消息。有一种例外就是:假设我们设置了 Visibility Timeout 是 30 秒,客户端 1 获取到消息后,消息变为 In Flight 状态,但 30 秒后仍然在处理过程中,此时消息回到Available 状态,客户端 2 也能获取到该消息,这也会造成单条消息的重复处理。解决的办法之一是适当延长 Visibility Timeout 的时间,给予第一个客户端更充分的处理时间。 Read More写下此篇流水纯粹是为了重拾那些零星的记忆,只能建立起一个模糊的脉络,找不回具体的时间点了,现在也是试着能否从某些日志里寻回些线索来。本篇日志最早创建于 2014 年 2 月份,中间偶有修改,却一直在草稿箱里静静的躺着。终于又时隔多年首次放出一篇非技术文出来。
1. 开始的开始,2001 年工作起,进入一个几乎完全陌生的程序世界。为了奋力从大海洋中汲取营养,大跃进的方式学习,并坚持在笔记本上面现在看来像是抄写一样的记笔记,不觉几年功夫,工工整整,满满的记载了四五本笔记本。还有看到那些好的东西也爱打印下来,其实打印出来的东西与它在网络上是一回事,没完整看的还是没看完,写下来了可不一样。这样记笔记的习惯其实也是工作之后的事情,上学期间最爱在课本上记东西。
2. 到后来是网络的盛行,也是信息量的爆炸的时代,再系统再全的书籍也无法与 Google 相比了。所以大概是 2005 年想到了在 QQ 空间里记了三五篇,一块娱乐之地上记录这些东西格调十分不搭。
3. 找到了第一个真正意义上的 BSP,那就是 blogcn.com,它现在完全变样了。QQ 上的几篇只需要复制到编辑框保存就行,那应该是 2006 年的事情。blogcn 是个综合性的 BSP,不好玩,代码高亮用工具保存成的带样式的 HTML 代码,好像也只在这里折腾了一年多时光,到 2007 吧,继续寻租。 Read More