帐前卒专栏

code, software architect, articles and novels.
代码,软件架构,博客和小说

经常遇到HttpClient 发送请求后莫名卡死, 然后经历很长一段时间后,返回response 为null。

这里设置了retry, 另外connect time 也设置的挺长的。但是还是出现了这个问题。

开始以为是Server的问题,Server不稳定导致了HttpClient无法连接。后来发现其实不是这个问题。这个问题的其实是必现的,如果将链接请求数调小的
话。但是发送的请求都在一个线程中,不会是线程争抢导致。后来找了许久,才发现,是连接忘记了关闭。

在HttpClient 4.0+的版本,正确的关闭连接如下:

EntityUtils.consumeQuietly(response.getEntity());

记得这个最好放在finally块中。

在HttpClient 3.0+版本中,正确的关闭如下:

    private static void close(HttpMethod method) {
        if (method != null) {
            method.releaseConnection();
        }
    }

今天过去写的testcase在ant执行时failed,但是在源文件中直接以application方式运行却没有错。

原因在于下面两句话:

public static Set<Class<? extends XXX>> getPluginsInSameDir(Class<?> clazz) {
        String dirPath = clazz.getPackage().getName().replace(".", "/");
        System.out.println(dirPath);
        URL path = clazz.getClassLoader().getResource(dirPath);
        System.out.println(path.toExternalForm());
.....
}

第一句是要得到那个类所在的包路径,第二句是要得到那个包所在的具体路径。

以application方式运行得到的结果是:

\\ aa/bb/cc
file:/D:/works/project/bin/aa/bb/cc **
以ant方式执行Junit testcase得到的结果是:

** aa/bb/cc
file:/D:/works/project/build/classes/aa/bb/cc **
这两个结果差别还是蛮大的。关键问题是classLoader()那个家伙的查找资源的方式。这里解决问题的最简单方式:

就是那个testcase中传入的Class<?&rt;clazz的包路径不要在testcase代码中出现(可以在src代码路径中出现),那么ant执行testca
se时,就又会找到原来的/bin目录。

例如工程结果是:

src/java
            | aa     
                  | bb
                        | cc
                             |YourClass.java
src/test
            | aa
                  | bb
                        | cc
                             | TestYourClass.java

你这里就不应该将YourClass.class作为参数传入进刚才的函数中。不应该像这样

getPluginsInSameDir(YourClass.class); 

最简单的做法是:

src/java
            | aa     
                  | bb
                        | cc
                             |YourClass.java
src/test
            | aa
                  | bb
                        | ccs
                             | TestYourClass.java

这是非常的土的方法。

你当然可以尝试修改一下getClassLoader().getResource()这句话。

这个问题产生的原因是:

ant执行JUnit时,执行TestYourClass, 这时加载的classLoader()是junit的classLoader(),
这个会首先在自己的包路径中查找是否有该路径,如果存在就返回了。

另外一种解决方法是:

        ProtectionDomain pd = clazz.getProtectionDomain();
        CodeSource cs = pd.getCodeSource();
        String location = cs.getLocation().getFile();

这样就能真正的通过那个类找到那个类 编译为class文件所在的目录。

其实 帐前卒 自己就听了第一天,第二天把票让给了其他的同事。

第一天总结为 easy -> difficult, and difficult -> easy.

1. 为啥是easy -> difficult. 是因为简单的事情都被做完了,只剩下难事需要做。要想发文章,要想上讲台,你再讲如何写HTML, 如何写C语
言,这早就out了。你要讲还是在同构的集群上做分布式开发,大家一听就厌倦了,也难登讲台了。要不就换个名词,吸引下眼球,要么就做得和别人不一样。做别人以前没有
做过的事情。这就可以讲了。所以开发会越来越复杂。

2. 为啥是difficult -> easy. 就是以前手工干的事情,现在可以机器做,而且及时手工做也需要便捷。比如飞机上的几百个钮,如果你的软件也做上
上百个按钮在那里,肯定没有人用了。你给一个按钮,做完所有的事情,那多简单。软件需要傻瓜化,就像windows, ubuntu占领了绝大多数桌面端一样。

下面 帐 前卒 用有道云笔记记录下来了基本的内容:

1. 我从KDD那个部分开始听的, KDD, 这次加入了时间维度,我记得过去推荐算法中是有考虑时间维度的。当然对KDD比赛没有了解,不做讨论。

2. 下面是AMD的异构模型。其准备将java字节码转义为openCL语言,然后在各个平台上通用。当让能直接支持java字节码的还是让它跑java.
这个只能说语言的通用性,但是对于性能不一的异构集群,如何使用同一套代码完全发挥各个机器的优势,这又是以后的难点吧。如果只Print hello world,
这个自然够用了。

3. 下面有电信的平台商来推广自己的天翼开发平台。不管怎么说,各个运营商的流量是相当的强劲。不过基本被几大应用所占据。一般小应用对于流量也不敏感。
帐前 卒
查看了一下天翼的API, 发现还是有很多不错的API, 授权也可以使用通用的Oauth2.0,
API中也有不错的。 如果现在对于各个API的流量免费的话,貌似有合作的空间。

4. 下面是盛大的来讲webOS东西,感觉没啥收获。貌似就是Linux + (JS, CSS, HTML) 渲染引擎。

5. 另外Amazon的truk听起来貌似不错,各位可以在上面挣点小钱。

6. 下面是twitter的部分。使用 mesos 来控制资源分配,
另外支付宝使用的 OpenStack , 这两个都是开源的可以学习一下。

7. 支付宝系统的演化做得不错,每一步都合乎常理,另外最上层的GTM应该也需要放在不同的IDC上进行分布式。否则挂了就全挂了。
如果GTM是自己做的转发机制的话。另外支付宝做的mile database, 其实就是simple的分布式分片数据库,
原理和我当年参与的项目是一模一样的。另外支付宝在支付时没有使用锁,使用try, commit, cancel机制,这着实让 帐 前 卒
惊奇了一番。要知道,即使这样很有可能有数据不一致的风险呀.
除非系统在try的时候就把序列号加入到各个节点中,并且判断了是否可串行化。否则怎么可能try 完了直接commit, 结果就是对的呢?

8. netflix 在云基础(Amazon S3)之上做了视频流,算是cloud的应用成功范例。另外其无上限年假的确很神奇。不过我知道进去那里的员工,如
果真的这样休假,肯定被开除了。因为netflix还有一条做得足够好的员工是肯定会被开除的。只有做得非常好,才能留下来。这么说无上限的年假基本就是fake的.

9. 圆桌会议上讲的就是虚幻的了。其讨论关于云计算的问题,基本和我过去总结的一篇blog类似。大家可以 猛击这里
以及 猛击那里

另外转载注明是 帐前卒专栏 的。

其实即使说转载注明这句话,或许还是会被抹去的。

客车罐车相撞,业内人士认为应该把卧铺客车这个车种取消。

飞机相撞,我个人认为应该把飞机这个交通工具取消。
火车相撞,我个人认为应该把火车这个交通工具取消。

汽车相撞,我个人认为应该把汽车这个交通工具取消。

经个人经验所得,骑自行车和走路,也有撞到老人的风险。

所以应该让我国废除各种车辆,人民采用匍匐的前进方式,这样能有效减少各种灾难。

我觉得很快业内人士就会认可这一有效地建议。

这个错误是因为在初始化列表中初始化了非成员函数或者非基类

错误示例:

class A
{
protected:
int size;
}

class B: public A 
{
B(const A& a): ok(0), size(a)
{
    // error, 因为初始化了 size
    // size 是 a的成员函数,虽然被B所继承,但是仍然不能在初始化列表中初始化。
}
private :
int ok;
}

改成:

class A
{
protected:
int size;
}

class B: public A 
{
B(const A& a): ok(0)
{
    // success
    size = a.size;
}
private :
int ok;
}

这样就完全没有问题~

这个错误很大可能是由 const 类型的变量调用了非const类型的函数。

例如:

class A
{
public:
    int size() {// return somthing};
};

class B
{
public:
     int getSize(const A& a)
     {
           // error. a是const类型,必须调用const function.
           return a.size()
     }
};

改为:

class A
{
public:
    int size() const 
    {
          // return something.
    }
};

class B
{
public:
     int getSize(const A& a)
     {
           // success
           return a.size()
     }
};

这样就没有错误了.

最近有道云笔记实现了客户端长微博发送的功能。但是客户端只有windows版的。对于linux,
mac的用户,还需要再等一段时间。现在教大家如何使用web页面发送长微博.

首先用chrome打开note.youdao.com 登陆后, 然后F12, 点击放大镜
, 然后点击第二栏的缩略图
,然后看到这样一串
。将字串中的data-note-
id代替url中的p参数(note.youdao.com/yws/mapi/weibo/share?p=/a89GEFgoLuA/0240F3E037874
7DAB9A01ED4348EC0B0&weibo=sina&any=PC&method=gen)。然后将该url贴入浏览器,然后就会得到Json串,将js
on串中的url贴入到浏览器,就可以发送长微博了.

现在有道云笔记的长微博中还存在有些不足。

1.是有些字体的缺失,会替换为默认字体。

2.是某些特殊的html标签,解析不是很好。导致了整个图生成的相当诡异。特别是html中带有

标签的图,生成的都会有多多少少的问题。这个或许在后
续的版本中有些改善。

3.是因为有道云笔记自身的编辑器导致了有些html格式不标准。看起来有时候字体很诡异。

个人认为有道云笔记还有一些可以改进的地方。

1. 一个功能可能隐藏在某个细小的角落里。或者要点击多次才能找到可用的功能。

例如分享笔记链接中,要找到取消笔记链接。这多多少少要找一会。

2. 开始的时候,不是码龙很难使用。虽然有介绍

3.笔记附件不是让人很满意。因为同一个附件,放入笔记中会变成多个附件。这个很不爽,至少让我身边使用的人很不爽。

有道云笔记其他方面都还不错,继续关注使用中。

  • text/html mime 没有base64 编码问题

java mail api 使用MimeBodyPart.setDataHandler()不能对text/html进行正常的base64编码而是使用quote-printable编码。 错误的样本:

1
2
3
4
5
6
// add headers 不能在最前面,一定要放在后面,否则可能不能正确编码
mimeBody.addHeader("Content-Type", "text/html; charset=utf-8");
mimeBody.addHeader("Content-Transfer-Encoding", "base64");
DataHandler textDataHandler = new DataHandler(new ByteArrayDataSource(
message.getBytes("utf-8"), "text/html; charset=utf-8"));
mimeBody.setDataHandler(textDataHandler);

正确的样本:

1
2
3
4
5
6
DataHandler textDataHandler = new DataHandler(new ByteArrayDataSource(
message.getBytes("utf-8"), "text/html; charset=utf-8"));
mimeBody.setDataHandler(textDataHandler);
// add headers 一定要放在后面,否则可能不能正确编码
mimeBody.addHeader("Content-Type", "text/html; charset=utf-8");
mimeBody.addHeader("Content-Transfer-Encoding", "base64");
  • 发送到新浪等邮箱,图片看不到

rfc2045-2047中并没有规定Content-ID的形式必须是: Content-ID:的形式。但是新浪的邮箱服务解析得比较严格。所以在JavaMail Api 中使用MimeBodyPart 对其进行setContentID时必须加上"<>"。否则图片会看不到。例如:

1
2
MimeBodyPart tmpBodyPart = new MimeBodyPart();
tmpBodyPart.setContentID("<"+attachment.getFileid()+">");
  • html格式正文被163等邮箱当作附件,但是某些邮箱解析正常

这是因为html格式的正文并不是MultiPart中的MimeBodyPart,而MultiPart的第一个MimeBodyPart可能是附件。在添加html正文时可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//将html正文放入到mimBodyPart中
String html="<html>xxxx</html>";
MimeBodyPart mimeBody = new MimeBodyPart();
mimeBody.setText(html, "utf-8");
mimeBody.addHeader("Content-Type", "text/html; charset=utf-8");
mimeBody.addHeader("Content-Transfer-Encoding, "base64");

//创建mixed 和 related两种mime subType
Multipart mPartRelated = new MimeMultipart("related");
Multipart mPartMixed = new MimeMultipart("mixed");
mPartRelated.addBodyPart(mimeBody);
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setContent(mPartRelated);
// 设置为第一个 bodyPart,这样就不会再变为附件。
mPartMixed.addBodyPart(mimeBodyPart, 0);

// mPartMix就是最后要set到mimeMessage中的内容。
  • inline图片当作附件,或者inline图片在某些邮箱中显示了两次

有些是邮箱会将这个作为feature,但是有些不是。这时要使用这些邮箱来发一封类似的邮件来看到底是那个邮箱的独特功能还是你的bug. 如果是你的错误,那应该是你将inline图片和html直接包到mime/mixed中,其实应该放入到mime/related中的。 所以把这个错误改正,应该就ok.

  • 邮件中的文本,线上打开乱码

这是因为发送邮件的编码问题。文本的charset不要编码为utf-8,因为这样可能有非utf-8的文本放入到邮件中发送。所以要写二进制编码 Content-Type: application/octet-stream 然后使用base64编码。 这样大部分编码就解决了。但是qq等其他客户端会有问题,这是他们自己的问题.

摸索多次终于写出正确的java的关于email匹配的正则式:

1
2
3
4
5
6
7
8
import java.util.regex.Pattern;
import java.util.regex.Matcher;
Pattern emailPattern = Pattern.compile("^[\\w\\!#\\$%\'\\*\\+/=\\?{\\|}\\~\\^\\.\\-_]+@[\\w\\.\\-]+$");
Matcher m = emailPattern.matcher("[email protected]");
if(m.matches()){
// if match
}

注意其中的"-“,”+“等,这个在正则式中有特殊含义,如果”-“放在[]的中间,则表示从哪个字符到哪个字符,例如:[A-Z]。如果仅仅想表示”-“可能会出现,那么还要进行转移,所以就有”\-"这样的形式。 上面正则式的意思是:以字母或者数字\w或者以!#$'*+/=?{|}~^.-_开头的1…n个字符,1个@字符,以字母或者数字或者.-结尾的字符串.

0%