这是一个最基本的 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
最早的初衷是要研究一下运行 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
Akka 是什么?它提供了 JVM 上的 Actor 编程模型 -- 同时兼顾了并发与分布式。它由 Scala 编写的,替代了 Scala 本身的 Actor。Actor 视线程为重量级的资源,能够以少量的内存胜任更高的并发,类似的东西有纤程,协程。有一个数据对比是同样的 1GB 内存,可以创建 2.7M 个 Actor, 而线程只能创建 4096 个,仅供参考,当然 Java 也是会基于线程池来执行的。
Actor 增加了程序的灵活性,并减轻了复杂度(标准的赞美之辞)。
所谓 Action 编程模型兼顾并发与分布,是由于让你编程时可以不用考虑线程,线程配置成为部署的范畴; Actor 之间通信只能发送异步消息,Actor 可以分布在同一 JVM, 不同 JVM, 或是不同物理机器上。
因为 《Akka IN ACTION》中提供了第一个例子起点着实有点高,所以网上找来了一个了解 Akka Actor 的最简单例子,来自于 Simple Scala Akka Actor examples (Hello, world examples)。并非纯属翻译,主要是为了练手,所以不完全一致: Read More刚开始阅读 《Akka IN ACTION》这本书,刚开始是对
Revolution这个词翻译成中文是革命感到诧异,因为革命通俗来讲就是杀人的意思。至于Revolution英文解释不深究了,只是感叹何以颠覆性的变化就一定要杀人吗?也由此引出了编程中经常面对的
Concurrent(名词为:Concurrency) 和Parallel(名词为:Parallelism) 这两个词,基本上是认为它们是同一个意思。其实不然,下面慢慢道来。如果从英文字典对它们的解释也没有多大区别,差不多都是说同是发生,但字面上
Parallel多了一个平行的意思。所以在中文上,在计算机领域我们约定的翻译是- Concurrent(Concurrency) -- 并发
- Parallel(Parallelism) -- 并行
比如在多线程环境中它们的区别具体体现在:
并发:多个任务在同一个 CPU 核上按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。针对 CPU 内核来说,任务仍然是按细粒度的串行执行。也难怪在 Java 5 中新加的并发 API 的包名是
java.uti.concurrent。 Read More
Bash 环境
多数时候我们用的是 Bash, 比如个人的 Linux 不愿去定制,远程服务器的由不得你去定制,所以就从 Bash 说起。
默认键绑定
emacs, 操作是ctrl-x, ctrl-e在默认的 Bash 环境下,只要在命令行中按下
ctrl-x, ctrl-e就会把当前命令的内容调入到环境变量$EDITOR指示的编辑器(默认为 emacs)去编辑,编辑后保存退出就会立即执行。如果未安装
Emacs编辑器,在按下ctrl-x, ctrl-e会得到如下提示[vagrant@localhost ~]$
-bash: emacs: command not found如果希望使用
vi来编辑当前命令,就需要设置EDITOR环境变量,比如在.bashrc中加入export EDITOR=vi
那么在命令行中按下
ctrl-x, ctrl-e使用打开vi来编辑当前命令。注:Emacs 要用
ctrl-x, ctrl-c, 再回答y, 命令保存到临时文中; 而 vi 的相应操作是:wq, 至少这个操作上 vi 要简洁些。 Read More初衷只是为了记述一下在 Bash/Zsh 中怎么调用 Vi 编辑当前的命令,但一发挥便涉及到了 Bash/Zsh 的键绑定的话题,无法打住,只得另立新篇。这里也只说 Bash 的键绑定,不会有 Zsh 键绑定的内容。
什么是 Bash 的键绑定(keybing) 呢? 就是在 Bash 中的快捷键方案,即相当于某个 IDE 的快捷键配置,或者叫 Keymap。比如说 IntelliJ IDEA 中可选择的 Keymap 有 Eclipse, Emacs, JBuilder, Mac OS X, Mac OS X 10.5+, NetBean, Visual Studio, 以满足不同使用者的习惯。
相应的 Bash 也为我们提供了两种键绑定的方案,即 emacs(默认) 和 vi 键绑定类型。
Emacs 键绑定
我们大多数天天在 Bash 下无意识中使用着 Emacs 键绑定类型,即使可能从未用过 Emacs 本身。比如我们在 Bash 下的按键组合
ctrl + a 跳到命令行的开始
ctrl + e 跳到命令行末尾
!! 重复最后一个命令
ctrl + l 清屏操作,类似于 clear 命令
ctrl + c 中断/杀掉当前运行的进程 (SIGINT)
ctrl + d 发送 EOF 标记,这会关掉当前的 shell (EXIT)
ctrl + z 发送 SIGTSTP 给当前任务,使其挂起送到后台。(所以如果 vi 未正常退出,而是按 ctrl + z 的话,vi 进程还呆在后台它们都是来自于 Emacs 键绑定。是不是那么的熟悉啊? Read More

探索是否能以流式写数据到 S3
通常,在我们项目中用 Java 代码上传数据到 S3 是下面那样的操作
AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
s3Client.putObject("bucket_name", "s3key.txt", new ByteArrayInputStream("hello".getBytes()), new ObjectMetadata()); //ObjectMetadata 没什么特别的话可以为 null虽然 putObject() 的第三个参数是一个流,但它是输入流, 并非输出流啊。也就是说在执行该方法时必须把所有待上传的上据全部准备在这个输入流中,所以这里就直接用一个 ByteArrayInputStream 来包裹需上入到 S3 的数据内容。
当然 putObject() 也就无法像 FileObjectOutputStream 那样流式写入内容到文件中,因为 putObject() 前后都没有与 bucket 上那个文件上有联系。即使是用 PipedInputStream/PipedOutputStream 也不行, 比如说下面的代码 Read More

使用 Vim 官方网站的字典下载链接
下载字典:
下载页面:http://www.vim.org/scripts/script.php?script_id=195, 当前下载链接为 http://www.vim.org/scripts/download_script.php?src_id=6351
解压缩所需字典文件
tar xzvf ~/Downloads/engspchk.targ.gz CVIMSYN/engspchk.dict
使用 Vim 整理成字典文件
vim CVIMSYN/engspchk.dict
删除前面三行:
gg3dd
删除行首 GoodWord单词::%s/^GoodWord\t//g
整理成每个单词占一行:%s/\t/^M/g,^M的输入要用ctrl-v再按回车键,也可以用ctrl-v-m来输入^M.
删除最后一行:Gdd
排序::sort现在的 engspchk.dict 中文件每一行只有一个单词,并且按字母排好了序的 Read More
我们可以用自定义的 URLClassLoader 从外部动态加载类,并使用它。但数据库驱动的管理类 DriverManager 却不比较苛刻,不承认非当前应用系统加载器加载的驱动类。见 DriverManager 的 JavaDoc
When the method
getConnectionis called, theDriverManagerwill attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application对于有有应用自定义类加载器加载数据库驱动类的需求时,就要对原 Driver 简单包装一下。继续往后会说介绍为什么要这么做。
说明一下,DriverManager 能够根据 JDBC 连接字符串匹配到驱动类,所以一般来说都不需要显式调用 DriverManager.registerDriver() 方法。
先看 DriverManager 在应用外部驱动类时会出现什么情况 Read More