已经出售,谢谢

转让自用的 13 寸 MacBook Pro,2009 年年中的款,型号 MB990,入手时间 2010 年初,使用时间三年不到,除了电池的续航能力有所下降,其他没有出现任何问题,内存我自己升级到了 8 G,平时的开发也都是用这台开发(你知道开个 Eclipse 或者 Intellij IDEA 是很耗资源的),也比较顺畅,价格方面是 2500,当然可刀~,暂时只接受杭州的当面交易。

有意向的可以直接在这篇博客下面回复,或者给我发邮件联系我,hting1#gmail.com

关于这个型号的 MBP 的其他参数,可以直接看下面这张图:

image

上几张本本的照片:

合上后,有些许划痕

image

image

Google 的 Guava 库是一个 Java 程序员必须了解的库,它提供了一些非常强大的功能,比如函数式风格的集合操作,Cache Builder 等等的功能,另外 Google Guava 还提供了一个非常方便的观察者模式的实现:EventBus。这篇文章就来介绍一下 EventBus 的使用。

EventBus 对象

在举例说明 EventBus 的使用方式之前,我们先来看一下 EventBus 对象,EventBus 对象整个负责了观察者模式监听者的注册,事件的分发,所以,在使用 EventBus 的时候,你就省去了非常多的工作,你只要去使用 EventBus 就可以了,不用再去自己实现一个 Publisher 的类,使用 EventBus 的第一步就是你需要一个 EventBus 的实例:

1
EventBus eventBus = new EventBus();

注册监听者

使用 EventBus 监听事件,只需要在你的处理事件的方法上添加一个 @Subscribe 注解就可以:

1
2
3
4
5
6
static class Subscriber {
    @Subscribe
    public void subscribe(Event event) {
        System.out.println(event.getWord());
    }
}

这里的事件对象 Event 可以是任何的对象,可以是 Object,但是也可以是任何你自定义的消息对象。

建立一个类以后,就可以往 EventBus 中注册 Subscriber:

1
eventBus.register(new Subscriber());

分发事件

在注册完事件后,就可以去分发事件了,分发的代码非常简单:

1
eventBus.post(new Event("Hello world"));

这样,所有的注册在 EventBus 中的监听者,只要它的监听方法的参数是 Event 或者 Event 的超类,那么都会收到事件。

结论

EventBus 作为一个 In-JVM 的观察者模式的实现,非常使用,使用起来非常简单,可以减少不少的工作,建议在项目中可以多多使用。

前一段时间特别喜欢上知乎,觉得还是一个挺有意思的网站,同类的国外网站有 Quora,不过我英语不太好,所以平时还是喜欢逛逛知乎,但是最近逛知乎的时候发现一个问题,里面的有一些的问题的高票答案其实不是在回答问题,而是在发泄自己的情感,而这些答案往往还能够得到高票(历史上的煽动家大概也是这样的,让自己的话迎合大众的情感,以此得到他们的支持),比如下面这个:

image

正常的答案应该是列出邹孟睿的经历,但是得票第一的回答其实是在表达自己对「来往」这个产品的不满,或者是觉得「来往」并没有什么未来,当然,他自己似乎也有点不好意思,所以用了「匿名」来回答。

知乎上的这种答案不止这里一个,还有很多讨巧的答案,作为一个问答网站,其用户对于问题的回答应该尽量保持中立,这样的答案毫无疑问是无异于网站的形象,所以现在知乎对我的吸引力也越来越少了。

既然提到了快感,顺便说一句:“阅读新闻也是一种快感”,这是浪费时间的快感,不看新闻,你也不会错过任何重要的消息,所以,不如把手机上的新闻客户端给删掉,它不能给你带来任何东西。

哦,对了,有一个新闻客户端,素以评论见长,它提供了另一种形式的快感发泄,是的,我说的就是「网易新闻」。

简介

jvmtop 是一个分析工具,顾名思义,它是一个针对 jvm 的 工具,展示的方式和 unix 的 top 命令相似。

jvmtop 的项目地址是:jvmtop,安装 jvmtop 除了项目地址上的方式以外,还可以通过 jenv 安装:jenv install jvmtop

jvmtop 提供了两个视图,一个是概览视图,可以展示出当前机器的所有的 JVM 的情况,命令是

1
jvmtop.sh

显示出的信息类似下面这样:

image

其中,各个字段的意义分别如下:

  • PID:进程 ID
  • MAIN-CLASS:main 类的名字
  • HPCUR:当前被使用的 heap 的大小
  • HPMAX:最大可用的 heap 的大小
  • NHCUR:当前被使用的非 heap 大小(比如:perm gen)
  • NHMAX:最大可用的非 heap 大小
  • CPU:CPU 的使用情况
  • GC:消耗在 GC 上的时间比例
  • VM:JVM 的提供者,大版本号,小版本号,图中的意思是 Apple 提供的 JDK 6U51 版本。
  • USERNAME:当前的用户名
  • #T:线程数量
  • DL:是否有现成发生死锁

还有一个视图是详情视图,展示一个 JVM 的详细情况,使用的命令如下:

1
jvmtop.sh <pid>

显示的信息类似下面这样:

image

其中,各个字段的意义如下:

  • TID:线程 ID
  • NAME:线程名
  • STATE:线程状态
  • CPU:线程当前的 CPU 占用情况
  • TOTALCPU:从线程被创建开始总体的 CPU 占用情况
  • BLOCKBY:阻塞这个线程的线程 ID

更加详细的用法大家可以用下面的用 jvmtop.sh -h 来查看。

实现

jvmtop 的实现相对来说还是比较简单的,整个 jvmtop 才 14 个类。

image

其中 JvmTop.java 是入口类。

jvmtop 在启动后,会首先用 sun.jvmstat.monitor.* 下面的类以及 com.sun.tools.attach.VirtualMachine 获取到当前机器的所有的 JVM,然后通过 attachment api 将 management-agent.jar 这个 agent 加载到目标 JVM 上,这样,通过 JMX,就可以拿到当前的 JVM 的各种信息了,具体各个信息需要用什么样的 MBean 去拿,大家可以看对应的源代码。

其实,如果需要一个 JVM 的静态的信息,比如,PID,MAIN-CLASS,JVM-ARGS 等等静态信息,直接用 sun.jvmstat.monitor.* 下的 API 就可以,只有需要动态信息的时候,我们才需要通过 attachment api 把 JMX 的功能打开,通过各种 MBean 去获取这些信息。如果后续需要实现类似的功能,也可以通过这样的思路去做。

image

今天和朋友聊天,说起眼见的问题,以前在业务团队的时候大家都奔着业务而去,完成业务上的需求,最多了解一下所用到的框架,鲜有关注业界的开源软件的动态。

而到了中间件团队,所有人都得规划、实施、推广自己的产品,如果只是做一些平庸的事情,那实在对不起你所在的团队,所以只能硬着头皮去花时间关注业界的开源软件的动态,慢慢地,也就开阔了自己的眼见,碰到一个问题以后,发现还可以用这样的方法解决,这是之前从来没有想到的。

最近其实一直在反思,当时这么快下决定转岗到现在的部门到底对不对?诚然,当时转岗的决定,有其他的非常私人的考虑,在新的岗位,各种不习惯,但是这里有很多新鲜的事情,可以作为学习的对象;有一些很强的人,可以作为学习的榜样。当你进入了一个更大的世界,你又重新回到了婴儿的时代,疯狂快速地吸收着周围的一切。

晚上跑步的时候突然想起了 Clyde 三年前和我说的他的梦想:“等我老了的时候,我希望成为一个讲故事的人”,当时我并不明白他到底想表达什么,只能随便应付几句。现在,我似乎有点想明白了,那些有着很多精彩的故事的人,无非就是旅行家,船员之类的,想要成为一个讲故事的人,必须有足够的人生经历,和这个世界有更大的交集。最近在看德田秋声的「霉」,永远待在一个地方,生活大概就像「霉」中的男女主人公过的那样,平淡,烦躁,偶尔有点阳光,能够讲述的大概也就是些平淡无奇的故事。

一直很佩服身边的一些朋友和同事,他们能够把一件事情坚持两三年,有些人跑地并不快,但是他们总能比你更加坚持,跑得更远,和他们相比,我的生活是不是太过肤浅,似乎从来没有坚持一件事情超过一年,对于那个超过一年的世界,我陌生无比,这大概是因为我一直都比较缺乏意志力和专注力。

旧世界纵然舒适无比,但是前方永远有一个更吸引人,更宽广,更深邃的世界,多年以后,希望在那个世界遇见更好的自己。

今天的工作基本上就是在重构实习生写的 JS 代码,改的昏天暗地,他们基本把整个工程的 JS 代码都放到了一个文件中,代码中一会儿以空格缩进,一会儿以 tab 缩进,到处都是不必要的变量,我的代码洁癖又犯了,忍不住直接进行了重构,对 JS 进行模块化的拆分,每一个模块都有相对独立的功能,改了之后舒畅了很多,就像拿掉了卡在喉咙中鱼刺。

工作这几年以来,我也遇到过几个和我一样,有着或者或少代码洁癖的人,看到 IDE 中出现的警告信息就会感到不舒服(从 Eclipse 转到 Intellij IDEA 以后,洁癖的程度越来越严重了,Intellij IDEA 会对你的代码风格做更彻底的检查),看到以 tab 来做缩进简直就像看到异教徒一样,看到代码中已经被注释掉的废弃代码那肯定得马上删掉。

可惜的是,工作遇到的更多的人,在这方面要随意的多,他们更多追求的是把工作完成,让功能能够跑起来,其实一定程度上来说,他们是对的,他们是更加实用主义的程序员,实用主义能够帮助我们更快地达到自己的目标,而不会被和目标无关的东西所牵绊。但是,我觉得,一个程序员在追求程序的实用主义的时候,也应该去追求程序本身的美感。

或许有人会问,什么是程序的美感,关于这一点,我们可以从很多的侧面去描述:

  • 更人性化的用户体验
  • 更简洁的架构
  • 程序内一致的代码风格
  • 更易读的代码

但是,“美”本身是用语言是无法完整描述的,你可以说娜塔丽•波特曼很美,你也可以说加西莫多很多,但是他们之间的差距是如此之大,除了他们都是人之外你都找不到他们的共同点。所以“美”就是“美”,只有你身在其中的时候你才能够感受到。

或许对于很多人而言,“代码美”根本就是个扯淡的东西。其实写代码的过程和做木工的过程是很像的,说白了,都是设计出一样东西,然后拿来用而已。看看下面的无印良品木制家居,不得不承认,它比我们平时从市面上看到的普通的木制家居要舒服地多。同样一段代码也可以比另一段代码看起来更加“舒服”,更加“美”,只是每一个人对这种“美”的感受能力不同而已,有些能够感受到,有些不能感受到(在这一点上,不得不承认,我对“代码美”的感受能力是比较差的)。

image

想要去培养这种对“程序美”的感受能力,一个很好的方式就是去阅读优秀的开源代码,比如 Tomcat,Dubbo 等等,有时候,当你看到一段不错的代码,一个简洁的有用的架构设计的时候,你会感到来自内心深处的愉悦,这就是“美”的一个侧面。我相信,培养这样的感受能力,是非常有益于身心健康的,并且我也相信那些透露出“美”的代码在某种程度上也是更加优秀的代码(内王而外圣)。

这个世界已经够丑陋了,如果我们已经解决了温饱问题,又有了这么多的自由时间,不如做点“漂亮”点的东西出来,写一些更有用,更“美”的代码出来~

image

近日在读阿兰•德波顿的「写给无神论者」,里面提到基督教的人性本恶的观点给人带来的好处,当你对一件事情的结果期望并不高的时候,那么当结果出现一点好处的时候,你就会感到很快乐;相反,当你对一件事情有着过高的期望,最后结果并不令人满意的时候,你就会感到失落,绝望。

德波顿这样捧高悲观,而贬低乐观有点太偏颇了。但是,在各种舆论阵地上,“悲观主义”都在被不公正地对待,各个社交网络上永远都是“正能量”,“乐观”,“积极向上”,每一个人似乎都非常排斥“悲观主义”,我想悲观的人大概也比较受人讨厌。

诚然,过分地悲观会无情地伤害你的心灵,太宰治(愿我们都不要成为他那样的人)笔下的叶藏就是个典型的例子,由于对人类普遍的失望,叶藏一直都是郁郁寡欢、懦弱怕事,不断地和遇到他的女子殉情,最终失去了为人的资格。但是适度地悲观是非常有善的。现实是现实,到了一个人的心中,就成了“心中的现实”。当一个人处于乐观的状态下的时候,往往会对高估了现实的状况,而轻微悲观的人“心中的现实”更加接近实际的现实,他们能够更加准确地估计到现实中可能存在的一些问题,并且做好相应的准备,在问题真正到来的时候不会惊慌失措,因而能够保持更加稳定,更加健康的心理状态。

而那些盲目的乐观主义者(我们的周围不缺乏这样的人),由于对现实有着过高的认识和期望,对问题认识不足,月盈而亏,当结果不尽如人意的时候,各种负面情绪就会出现。你以为你有光明的未来,以为有特殊的才能,但是,到最后却发现你不过是芸芸众生中平凡的一员,很多中年人的失落就是来源于此吧。

所以,与其做个乐观主义者,不如做个悲观的行动主义者,与其相信有那种可能性,不如自己去寻找那种可能性,并且为可能的失败做好准备(成功永远都是属于少数人的)。

有一次和 @imsoz 在聊天的时候,他给我介绍了一个叫做 Git flow 的分支管理模型,我听了很有兴趣,于是昨天花了一点时间去了解了一下。

Git flow 分支模型

Git flow 是一个分支模型,它提供了一个经过实践检验的分支管理的模型。整个分支模型的工作图大概是下面这样样子的:

image

它包含有两个长期分支和三个支持的分支:

  • master 分支:使用过 git 的同学应该都这个分支很熟悉,这个分支代表了可以用于生产环境的代码。
  • develop 分支:用于开发的分支,或者叫做“集成分支”,这里的代码可以用来做 nightly build。

上面两个是长期的分支,这两个分支在开发的过程中会一直存在下去。除了这两个长期分支,还有三个用于支持的分支:

  • feature 分支:一般上从 develop 分支拉出来,最后要 merge 回 develop 分支,或者废弃掉。feature 分支是用来开发一个在下一次的产品 release 中可能被加上去的特性的,一个 feature 分支在特性开发完毕后就结束了,所以 feature 分支只是短暂地存在。
  • release 分支:release 分支用来支持准备一个将要被 release 的产品版本,在这个分支上,我们可能会修改版本号,做一些 release 相关的事情,或者做一些 bug 的 hotfix,release 分支从 develop 分支拉出来,当你认为你的下一次的 release 所需要的特性都已经开发完毕的时候,你就可以从 develop 分支拉出 release 分支来,最后 release 分支需要 merge 回 develop 分支和 master 分支。
  • hotfix 分支:顾名思义,hotfix 分支就是当生产环境的代码出现了重大的 bug 的时候需要的分支,这个时候你可以从 master 分支中拉出一个 hotfix 分支,在修复完 bug 后,记得要把 hotfix 的分支合并回到 develop 和 master 分支上。

上面就是 Git flow 的整个分支模型,相对来说还是比较简单的,更加具体的说明可以看这篇关于 Git flow 分支模型最原始的 blog:http://nvie.com/posts/a-successful-git-branching-model/

Git flow 扩展

但是有一个问题就是上面的这些分支的创建,合并,删除等等操作,都是需要好几步的,比较费时间,费精力,Git flow 还提供了一个 git 的扩展,让我们可以非常方便地在项目中使用上述的分支模型,具体的使用方式作者都已经写在了 github 上,大家可以自己去看:https://github.com/nvie/gitflow。在 Mac 下可以用 brew install git-flow 来安装。

之前我也了解过 git 的一些使用,并且已经在一些项目中尝试去使用 git,但是在分支管理这一块一直比较头疼,而 Git flow 恰好给我提供了一个现成的经过实践的分支模型,刚好公司后面有一个项目可能也会用到 git,到时候我会尝试下在项目组中推广使用 Git flow,让实践去检验一把。

Velocity 对 Java Bean 中布尔类型的属性的获取问题

今天朋友遇到一个问题,是 Velocity 下面一个 Boolean 类型的变量在模板上没有办法输出,我大致简化一下这个问题,现在我们有一个简单的 Java Bean:

1
2
3
4
5
6
7
8
9
10
11
public class SimpleBean {
    private Boolean hasKatong = false;

    public Boolean isHasKatong() {
        return hasKatong;
    }

    public void setHasKatong(Boolean hasKatong) {
        this.hasKatong = hasKatong;
    }
}

然后有一个简单的模板:

1
$simpleBean.hasKatong

模板合并的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) throws Exception {
    Properties p = new Properties();
    p.put("resource.loader", "class");
    p.put("class.resource.loader.class",
        "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
    Velocity.init(p);
    VelocityContext context = new VelocityContext();
    context.put("simpleBean", new SimpleBean());
    Template template = Velocity.getTemplate("mytemplate.vm");
    StringWriter sw = new StringWriter();
    template.merge(context, sw);
    System.out.println(sw.toString());
}

大家猜测一下这段代码的输出会是什么?可能大多数人都会认为是 false,但是在 Velocity 1.5 下,这段代码不会输出任何东西,反而会有一个 Warning:

INFO: Null reference [template ‘mytemplate.vm’, line 1, column 1] : $simpleBean.hasKatong cannot be resolved.

而在 Velocity 1.7 下,输出就是如大家所预测的那样,是 false

具体的分析过程并不复杂,Velocity 1.5 和 1.7 在寻找 isXXXX 这样的方法的时候处理稍微有一点不一样,具体在 BooleanPropertyExecutor 这个类上,在找到方法,对方法的返回值的判断上有一点不一样,1.5 是这样的:

1
2
3
4
5
if (isAlive()) {
    if (getMethod().getReturnType() != Boolean.TYPE) {
        setMethod(null);
    }
}

而 1.7 的是这样的:

1
2
3
4
5
6
7
8
if (isAlive())
{
    if( getMethod().getReturnType() != Boolean.TYPE &&
        getMethod().getReturnType() != Boolean.class )
    {
        setMethod(null);
    }
}

可以看到,1.7 中增加了对返回值是 Boolean 的支持,而 1.5 只支持返回值是 boolean 的方法,那么既然知道了问题的根本原因,解决方法就显而易见了,要么将 hasKatong 这个属性的类型从 Boolean 改成 boolean,要么修改下 velocity 的模板,将属性获取直接改成方法调用:$simpleBean.isHasKatong()

Java Bean 规范对布尔类型属性的定义

当然,照理说像 velocity 这样的著名开源组件,不应该在这种问题上犯错误,然后我看了一下 Java Bean 的规范:

image

其实这段话已经说的很清楚了,只有原生类型的 boolean 的 Accessor 方法才能够用 is 前缀,其他的都用 get,其实在 JDK 的 Introspector 的实现中,也是这样处理的。

那么,这么看来,Velocity 1.5 的处理是正确的,那么 1.7 增加对 Boolean 的支持是为什么呢?

其实,Java Bean 的规范在 is 这种 Accessor 的规定上,是有点不怎么符合开发人员的直觉的,很多人都会在这个问题上纠结:Boolean 类型的属性的 Accessor 是不是应该用 is 开头?,我觉得大部分人的直觉对这个答案的回答应该都是,所以 Velocity 这样处理只不过是顺着大多数人的直觉的意思罢了,无可厚非。