My Octopress Blog

life and I

SQL笔记

| Comments

Basic

store_name Sales Date
Los Angeles $1500 Jan-05-1999|
San Diego $250 Jan-07-1999|
Los Angeles $300 Jan-08-1999|
Boston $700 Jan-08-1999|

select SELECT store_name FROM Store_Information

DISTINCT SELECT DISTINCT store_name FROM Store_Information

WHERE SELECT store_name FROM Store_Information WHERE Sales > 1000

AND OR SELECT store_name FROM Store_Information WHERE Sales > 1000 OR (Sales < 500 AND Sales > 275)

IN

SELECT * FROM Store_Information WHERE store_name IN (‘Los Angeles’, ‘San Diego’)

BETWEEN

SELECT * FROM Store_Information WHERE Date BETWEEN ‘Jan-06-1999’ AND ‘Jan-10-1999’

LIKE

SELECT * FROM Store_Information WHERE store_name LIKE ‘%AN%’

ORDER BY

SELECT store_name, Sales, Date FROM Store_Information ORDER BY Sales DESC

function

  • AVG (平均)
  • COUNT (计数)
  • MAX (最大值)
  • MIN (最小值)
  • SUM (总合)

SELECT SUM(Sales) FROM Store_Information

COUNT

SELECT COUNT(store_name) FROM Store_Information WHERE store_name is not NULL

GROUP BY

SELECT store_name, SUM(Sales) FROM Store_Information GROUP BY store_name

HAVING

SELECT store_name, SUM(sales) FROM Store_Information GROUP BY store_name HAVING SUM(sales) > 1500

ALIAS

SELECT A1.store_name Store, SUM(A1.Sales) “Total Sales” FROM Store_Information A1 GROUP BY A1.store_name

参考

教程

Slice Reading 080112

| Comments

Gizzard

Gizzard 这是一个Twitter开源的管理Mysql分片以及集群的方案。对Mysql一定加强

Twitter Mysql

Twitter Mysql 这是Twitter开源的后台记录数据的开源数据库,基于Mysql二次开发,对大数据处理做了优化

Zipkin

Zipkin 这是Twitter开源的分布式查询系统。利用了Facebook的开源日志系统Scribe。Twitter用其查询系统性能瓶颈,对系统进一步优化, 比如memcache请求,mysql重写太慢的select,以及部分服务超时。以 Apache Cassandra 为后端存储,Zookeeper前端协调。

Weka

Weka是一个用java写的开源的数据挖掘软件,类似SPSS。

相关参考书籍

数据挖掘:实用机器学习工具与技术(英文版•第3版) 机器学习

Thrift

| Comments

简介

[Apache Thrift][at]是一个跨平台的可伸缩的网络服务开发平台。通过其代码生成器 生成的不同语言的代码可以用类似的接口进行调用。支持语言如下

  • C++
  • Java
  • Python
  • PHP
  • Ruby
  • Erlang
  • Perl
  • Haskell
  • C#
  • Cocoa
  • JavaScript
  • Node.js
  • Smalltalk
  • OCaml
  • Delphhi
  • other…

编译安装

参见Debian or Ubuntu setup

创建Makefile

默认

1
./configure

但是生成的在本机遇到两个问题

erlang

通过git下载jsx失败

解决:通过配置项去掉erlang支持

1
2
3
4
5
6
./configure --without=erlang

**ruby**
ruby_noexec_wrapper错误

解决:通过配置去掉ruby支持

bash ./configure –without=ruby

1
2
3
4
**依赖库**
libboost

如果安装了libboost,需要指定其库位置

bash ./configure –with-boost=/usr/local

1
javac

bash ./configure JAVAC=/usr/bin/javac

1
###编译

bash make

1
###安装

bash make install

1
2
3
4
5
6
7
8
###可能问题

**compiler/cpp/thriftl.cc:2190: undefined reference to yywrap'”**
需要安装 Flex library 

**mv: cannot stat “'.deps/TBinaryProtocol.Tpo': No such file or directory”**

重新配置

bash –enable-libtool-lock

1
###安装

bash make install

1
2
3
4
5
6
7
##自带教程


###C++

自带教程在根目录的tutorial目录中,包含了一些常用语言的例子。以c++为例,
进行如下操作

bash $ thrift -r –gen cpp tutorial.thrift $ cd Cpp $ Make

1
2
3
4
5
6
7
8
9
10
**htons, htonl找不到**
解决:需要添加宏定义-DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H

**undefined reference to `apache::thrift::transport::TServerSocket::TServerSocket(int)'**
解决:将-lthrift移动到最后

**修改boost包含目录**
因为boost 1.49以后安装目录和1.33不同,需要确定后修改相关定义

最后Makefile修改如下

Makefile BOOST_DIR = /usr/local/include/boost/ THRIFT_DIR = /usr/local/include/thrift LIB_DIR = /usr/local/lib

GEN_SRC = ../gen-cpp/SharedService.cpp ../gen-cpp/shared_types.cpp ../gen-cpp/tutorial_types.cpp ../gen-cpp/Calculator.cpp

default: server client

server: CppServer.cpp

g++ -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -o  CppServer -I${THRIFT_DIR} -I${BOOST_DIR} -I../gen-cpp -L${LIB_DIR}  CppServer.cp

client: CppClient.cpp

g++  -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -o CppClient -I${THRIFT_DIR} -I${BOOST_DIR} -I../gen-cpp -L${LIB_DIR} CppClient.cpp

clean:

$(RM) -r CppClient CppServer
1
###Java

bash $ thrift -r –gen java tutorial.thrift $ cd java $ ant

1
运行的话,直接运行

bash $./JavaServer & $./JavaClient

1
###Python

bash $ thrift -r –gen py tutorial.thrift

1
2
3
4
5
6
**import Thrift error**
没找到包路径,需要在~/.bashrc中添加export PYTHONPATH=/usr/lib/python2.7/site-packages/
然后重启terminal

**TypeError: getaddrinfo() argument 1 must be string or None**
修改如下

python transport = TSocket.TServerSocket(port=port)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
##教程

###The Missing Guide

####语法类型

#####Type

包含基本类型,用户定义结构,容器类型,异常以及服务定义

**基本类型**

没有无符号类型,因为很多生成语言不支持该类型,比如java

- bool: A boolean value (true or false), one byte

- byte: A signed byte

- i16: A 16-bit signed integer

- i32: A 32-bit signed integer

- i64: A 64-bit signed integer

- double: A 64-bit floating point number

- string: Encoding agnostic text or binary string

**容器**

因为容器的复杂性,thrift没有消息长度,但是过于复杂的容器会阻碍消息的编解码

- list<t1>: An ordered list of elements of type t1. May contain duplicates.

- set<t1>: An unordered set of unique elements of type t1.

- map<t1,t2>: A map of strictly unique keys of type t1 to values of type t2.

**自定义结构和异常**

自定义结构类似于c的语法,而异常类似于把结构定义中的struct变为exception

**服务**

和定义接口或者纯虚类一样

#####Typedef

类似c/c++

c typedef i32 MyInteger typedef Tweet ReTweet

1
#####枚举

c enum TweetType {

TWEET,       // 1
RETWEET = 2, // 2
DM = 0xa,    // 3
REPLY

} // 4

struct Tweet { 1: required i32 userId; 2: required string userName; 3: required string text; 4: optional Location loc; 5: optional TweetType tweetType = TweetType.TWEET // 5

   16: optional string language = "english"

}

1
2
3
4
5
和protobuf不同的是thrift不支持包含枚举(包含结构)。枚举值是32位的正数。

#####注释

支持shell, c/c++, java风格注释

This is a valid comment.

/ * This is a multi-line comment. * Just like in C. /

// C++/Java style single-line comments work just as well.

1
#####命名空间

c namespace cpp com.example.project // 1 namespace java com.example.project // 2

1
2
3
4
5
6
1. 在cpp中展开为 *namespace com { namespace example { namespace project {*
2. 在java中展开为 *package com.example.project*

#####引用外部文件

可以引用外部其他thrift文件,搜索目录为当前目录,需要注意的是,thrift文件后缀名为thrift,使用其他文件中结构时,需要加前缀

c include “tweet.thrift” // 1 … struct TweetSearchResult {

    1: list<tweet.Tweet> tweets; // 2

}

1
2
3
4
1. 后缀名为".thrift"
2. 使用Tweet结构需要添加tweet前缀

#####常量

c const i32 INT_CONST = 1234; // 1 const map<string,string> MAP_CONST = {“hello”: “world”, “goodnight”: “moon”}

1
2
3
4
#####定义结构

结构是thrift IDL的基础单元,每个结构由不同区域组成,每个区域有唯一的id, 一个类型说明, 一个变量名以及一个可选的默认值
下面是一个需要完成类似Tweeter的结构Tweet

c

struct Tweet { 1: required i32 userId; // 1 2: required string userName; // 2 3: required string text; 4: optional Location loc; // 3 16: optional string language = “english” // 4 }

struct Location { // 5 1: required double latitude; 2: required double longitude; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1. 所有区域id必须唯一且为正数
2. 区域需要标识为 *required* 或者 *optional*
3. 结构可以包含其他结构
4. 可以为变量选择默认值
5. 可以在一个thrift文件中定义多个结构

区域id为解析器标识不同的变量,一旦定义就不要修改。标识了required的变量但是没有赋值,thrift序列化时会报异常。如果标识了optional
且赋了默认值的变量解析消息时不存在,那么解析后的结构里面会对其赋予默认值。

对于将变量设置为required需要非常小心,一旦赋予后,改变它为optional会引起各种问题,老的解析器会因此报异常。部分使用者认为required
这种设置带来的问题比好处多,因此只使用optional或者repeat,但是这个观点并未被普遍承认。


#####定义服务

thrift定义了一个跨语言的RPC框架。可以帮助用户快速构建网络应用,这是thrift的一个主要特点。
其定义类似于java的接口定义,thrift会根据你选择的语言类型默认生成客户端和服务端代码。

c service Twitter {

// A method definition looks like C code. It has a return type, arguments,
// and optionally a list of exceptions that it may throw. Note that argument
// lists and exception list are specified using the exact same syntax as
// field lists in structs.
void ping(),                                    // 1
     bool postTweet(1:Tweet tweet);                  // 2
TweetSearchResult searchTweets(1:string query); // 3

// The 'oneway' modifier indicates that the client only makes a request and
// does not wait for any response at all. Oneway methods MUST be void.
oneway void zip()                               // 4

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1. 逗号和分号都可以作为结束
2. 参数必须带类型和id
3. 返回值必须带类型
4. oneway返回值必须为void

####代码生成

下面图标识的thrift的网络模型

{% img data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeoAAAEmCAIAAAAiJUSiAAAqT0lEQVR42u2dC1hVVcK/A8EQEy8hKmlYXtJKSpOyTMdLhikZ6ieiGaiDiqFmXjPvOhoKIV5QzG4zX9lM9U0+TuNYWWNFVpZFUXntQjHRTDfMpCj7/v/fafntjueyzwGMDvL+nvfhOXvt29r7nPPuddbZZ3HW/yOEEFILcxangBBC0DchhJAa1/f/EkIICfigb0IIQd+EEELQNyGEEPRNCCHomxBCCPomhBCCvgkhBH0TQghB34QQQtA3IYQQ9E0IIeibEEII+iaEEIK+CSEEfRNCCEHfhBBC0DchhKBvTgohhKBvQggh6JsQQgj6JoQQ9E0IIQR9E0IIQd+EEIK+CSGEoG9CCCHomxBC0Df6JoQQ9E0IIQR9E0IIQd+EEIK+PeUsQgghvhKg+t78/mYAAPCGPFlWVnbs2LHy8vKKiooTJ06gbwCA2qHv4uLi0tLSL7/8UhKXwdE3AEDt0HdRUdHhw4dLSkpkcLXB0TcAQO3Qd0FBQWFhoQyuNrga4OgbAKB26HvHjh0yuNrgxcXFZWVl6BsAoHbo+5FHHtm5c+fevXvVAP/yyy/RNwAA+kbfAADoGwAA0DcAAPpG3wAA6Bt9AwCgbwAA9I2+AQDQN/oGAEDfAADoG30DAKBv9A0AgL4BAAB9AwCgb/QNAIC+q67v/CP5cx+fOzB94GXXXdY3pW/SgiSeWgBA34Gub7lb1tYqYeeEdYjrEB4RHhQUxFMLAOg70PW9eOdiLR96dmjWq1kOmx/OX/j3hTy1AIC+A13fS55aouWDgoPmb5/v3jBPWpAU0yWmcVTjTtd0WvC3BaY8flL8hV0vnJw/OXFWYqv2rWZunTn8juEquWnGTda60/80XSUrdq+o1HZ4SQEA+q7EYbTu1FqrhNQPSZyZmLc/zyrvP7a/ytt3bz94yuCwc8LCGoblFuaq3HS2xFwaI+lHxUTNeHiGzKuS8MbhG97bYNa9fMDl0R2jK7sdXlIAgL4rcRhqI5930Xln/ZwWF7SY+/hcFd714l3B9YJFzr4cTfZK7qW5Y1aMsbSrJVftWWW10yPbRKrw92t+r8msV7O04oj5Iyq7HQAA9F25I9l4cOOwOcPqN6jv6AcPC1369NKMezIc32c2DIu7MU60ubiNJuMnxlvavXn5zc5bGHL7EBV2urqTHg+/Y3hIaMjdr9+tx5XdDgAA+q40y55ZFtE8QqsPnjI4fVO6UXn8pPiB6QMNk/Im/aLdP5yi3cyCzKDgIEVt+ZbtWnYb2M2UV3Y7AADouyp0vb6rVr9yyJXLn1tuulNm/2W2yzLetHtxr4tV3rlnZ/2dev9UU1iF7QAAoG/fyKqx/WKH3zF85taZSQuTQkJDtHpabppm9RjaQ48j20QOuX3I5PzJCdMSkhcn22g3bW2aMXXTlk03HdpklVd2OwAA6Ns3Mx6eEVwv+Kz/S3jjcKnczFr/zvoBaQNCw0LNrEbNGiVMTbDRbt7+PK2uWYMyBjmXV3Y7AADo2y/UUl75wso5j81Z+vRS5xsHrbtKNHfNG2uqebJO13YAANA3AAD6PiP0va5oXc2cODXDF+1YZO4ED4TtVIrlzy3XTte+tbYG1goozoBD+K1e8IC+f119p65O7TG0h80CfVP6tmrfasK6CdU/caer1/s36T2PuTRGO7118601sFZA4c8hnMYXSQ2QsSWj++Dua99ei8vQdy3Wt95vWmvU0lE2y0jujZo1Gps19rfS95o31sx7Yt6yXcvQ92nB/XxW/xBO44ukBg5t9curw84J69K3S/6RfHSGvmulvlftWaUXcdvYtvmHa+hFXDXt9h7dW2uZu1bQd/VxP59nzAcI/w8teXGyljR3sgL6rn36TpiWoFVue/A2M7n2rbWJsxI79+wcERnR5uI21ivbGiDQZTLlrpSYLjHturWzZpm7WW6YfEOLC1q0uLDFsLnDrp9wvRa2frnjol1vQxI6Mz5nvOpjbiq3xjK0tuOxDh5HNPS2L20/7sa4lu1aasm+KX0X71zsfCyDMgbpQMyxmN/9WxbztkH7texv0XHfYDXHdHQ/Px7Pp/stSTaH4PH0Or9ITnud/TxX3g4tLTet41UdtWRU26jYfrHWMWqxyDaRNMDRd63Ud/Pzm2uV7L3ZZvKa/7pGk5f0vmT0stH9UvtZ/3zHxblmUm+Ps8PPju4Q7bhnPCI878DJ+w5/d/PvVNKgUYPBUwbrw6m549t657tsytuQhM7IDkYfej/HT4w3o5Pb18HjiIbe9nX5gMuFrlU9k3qaw7d2rZOgEu1CZjG/KXU+Fm8btF/LBo8brM6Yjh7Pj8fz6YL9IXg8vc7P7Gmvs//nyv3QdB1SSXC94LiEOB1Xhys7WBvRc61Zcx6dg9HQdy3T98aDG/X20zvEKtGLXluwfrzjrafCTEr9xvuNzm2kSfMeNiMOalKtLbOweR961LfNkIR+dp54rMNmTyMa+rOv/MP5DZs0DAoKMtvUkiH1Hb9EnfbANNPcU0vTOhZvG7RfywZvG6zOmI7ezo99D4PPQ/A4YKTzM/tr1Nmfc+V+aKqheUFOXD/RwzVgnOMakJKZgtHQdy3Td9YrWVreahOJW1beYtpZasKkrk61fv7uUd9qoTt3jGZsybCaXfVC6q1/Z73HblPnTdkMSeinvl3qoFbbWV5iZnnc17qidaOWjuoxtEfnazsbbZkP3bP/Mtu02qz7E5yPxVvl7deyuxfC+9mo8piOHp8jn/r2eQgeB4x0eZGc9joLNTXO8h6zEZdDm3rfVPMvpawXpDOqmOYOnT0Uo6HvWqZv2VlvUb2RnAtn/XlW29i25v3QNb6rjb6tSee32ZR7p5h3i5r2PvVtMyRhZb+6dHmru3+x6W1fMpQZ8Ty2X2zCtAQjCKNv1dl437qMOR+Ltw3ar2WDzdmo/piOldK3z0Pw+L2xS+Fpr7Of58rl0FRouvKsF6TLzY6aOy57HEZD37Wv79t8KHb/nwnpGx1vD733Ml/KrJS+lz691KjffJ019/G5ZiRxj+98myEJPXZ06qNulfXtbV9GBB2v6mgmm0U3s/S94G8LzCrmX4Cufnm1+ThvjsXbBu3Xyno1a/ofp3vsELA/G9Uc09Hl/LifT/8PwU99n/Y6+3muXA7NekFa3887o89bmjXviXkYDX3XPn0PmzvM8Q655+Q7pFdyrxHzR8z76zy1R1Qu85ofp/mvb9EhroP56H1h1wsjmkc0bdnU8e69b6rHdb0NSejCtAemaTG5VbZ1/urSf31729f87fNV2Diq8fic8VcMukINRuvzu9qeLS5ooUkdhaQQFRNlhuWyLOZxg/ZrmbvsVeLt1mlvZ6OaYzq6nB/38+nyscz+wP3U9+mts5/nyv3Q9CHSHEvizERtTQ1zM7xP3oG8iMgItWDQGfqulfrO2ZfTqFkjvYLNR0s1lEwfcUj9EDWdrK8fK6XvrFeyYvvF6uNqu27t1AbXm99qjLuv621IQnehdB/c3dTNSKQK+va2r2tHXqvjlbh7j+p9/YTrzVxzQu7cdmfTVk3NLRCpq1Nd+hC8bdBmLaPvJi2aeHw6bM5GNcd0dDk/7ufTBfsD91Pfp7fOfp4r90PLLcxVu8SMh+zweGTEhncd98PcNOMmek7Qd+3+1aVaK0FBQWqGW7fTZr6UWZ0RIZzv9DIfXa1OGJt7eP0ZklA6qP7/xvS4L73Dra/psvdmOw+l4jghBZnOjUd/Nmizlq4QcQlx1T8b1VzF5/n0eeC/xhNxujbifmg6kBW7V1jPstaS+q8cciUuQ9+1e8wTNVLUPDldpyZ+Uvy5552rz7ZqBJlvAk/jxms7atVGd4w2N+TBbzvmSZ8xfdwHSQb0XftGHPT4vXzVmHrf1KuHXd26c+uGTRq2ubiN2vXWbzdA7cTTeKqhyvAsoG/G+wYAQN/oGwAAfQMAAPoGAEDfv76+CSGE2CcQ9a2UlZUVFxcXFRUVFBTs2LHjEUIIIadGbpQh5UnZUs4MFH0fO3astLRUl5TCwkLVbychhJBTIzfKkPKkbClnBoq+y8vL9VmgpKRENdO1ZS8hhJBTIzfKkPKkbCln0vdNCCG1I8XFxWp3y91qeldUVASKvkeMeAYAALyBvgEA0Df6BgCoQX0HaN83zw0AgL2+A/HOE/QNAOBT34F43zf6BgDwqe8A/dE8zw0AAPoGAEDf6BsAAH2jbwAA9A0AgL7RNwAA+kbfAADoGwAA0DcAAPpG3wAA6Bt9AwCgbwAA9I2+AQDQdw3p++6739q69Yjh/vsPZGYWJifv4okHAPQd6Preu/c/qtKJE/8rTPU+/fR4auo/ee4BAH3XAn3/8Y8Hb7752ayst0yFN258l+ceANB37dC3mSwuPqbJ//7vQ3q8bduHBw+WrV5duHXr4ZKSb5csed0sI7kfOPB1WVnFBx9889e/fijvW1vLzS16992vvvrqezXhX3/9c1OYlPTMgw8ePHLkqMrffvvLOXNeMeUpKf/UllWiTX344Tf333/Avtxm196qCgDou07oe8aMPabCK1a8Yc16//2j2mNp6XHjxCee+FCF33zzw+OPf/DJJ9/qsbyZlOToLleJJn/66X8LCj7bsePj9977yuzi738vVvn+/V9rgfLyH8vLT5jOmeee+5fKCwu/2LJlv5aX4s3y3sptdu2xqgCAvs98favJ/NZbX/744096rGav2svWLLWjJ016wSysB6aLfMGCvZpMTt713XcnNJmb+7Y1KyfnbeftT578ooQuxo/frcldu0q0TH7+e3p84ECZ1dJ3xmO5za49VhUA0Hed0Pfx4z9+9ll5UdGXauqOHv2s86x77tlvLXzXXW+qpKLiJ+vuFElfJdu3f7RypWPWDz/8NGbMc87bz8wsVLla3AUFpeLDD7/R5LZtH2mWJG5OyAcffJOX9+7IkSe36bHcZtceqwoA6Ltu9X27z7rnnveskuzst1Ry7NgPpnkuXnnl3yrZufNjM0uXAZf7DrOy3jLa3bbtwyeeOIkWNnMXLXrtyJGj5rRoU9Za7uU2u/ZYVQBA3+j7FydOn77HHMLtt+8xJV988b0mt2zZb836wx/ecN7I1KkvmfKFC1/zVgejZp2r9PQXvJXb7Bp9AwD69qFvq8176FCZNP3005/o8RdffHfLLc9Zs77+umLr1iOZmW8+9tj7ph/m+ec/Vflnn5X/+c9HVq8ufPTR983NJLt2lTz44MF5815dv/4dLfD99yfMdryV2+wafQMA+vah79TUfz777L/Mt4iqyTvvfHXbbS9Zs2Re8/2nUlZWYW7sGzPmue3bP6qoOFl+9GiFzK7yt9/+Umo2PeaFhV8sW7bPbMdbuc2u0TcA1Dl9V43k5F1TphQ43/HtMisl5TmX8qSkZ2699cWxY3e7FKanv+DybadNuf2uAQDQNwAA+g4kfXtsz/6GqD0+c+bL48bt5qXmkalTX9L5SUn5ZwA+dwDou+b0nZf37vPPf/rbntB//OPjTz751vppD33W9rz/vuPuyVWrCn++g/7NPXs+c++VAoAzXN8ypnZ9772/8Q9bdu/+9OjRig0b3qlT+h47dvcdd7w6bdpL1dH3xIkvlJf/uG/f59ad7wBw5uvbvPOPHDlqRggJHOqIvs1tjuZ+myrrW9x//wFN3nffAd6ZAHVF348++r7LD2o8Dg04wteQfosXv75165GPP/720KEyfZYfPfrZHTs+/uyzcn2ot5qW1uB/Dz10+OOPj5WUfGuNOeU816O+vY1N6M+AgsnJu1RhHc6//nX8oYcObd/+kVaxfivkc8ubNr2ruQcO/FK3ytZn3bqigoJSTQqdlhkzTv68SOU6nz/fpf691srIKLDZ8siRu/7nfz7QIZijMGMMWPrWXG3k3/8upwEOUFf0LcNqv2lpz5tJb0MD+hzST9Y+erRC+jC3db/55helpcePH/9Rk9qOs5HVbNQCmmsOed06z70lLpPexib0Z0DBp576xPxqX+vu2/e52a8lPvst6zC/++6ELkt6/O23P44a9WwV6qNCoabxs8+eHDHRbETXPGNhXRu2bfvIPAvetqzTqHJVRlcIad3lKITO+c/jdr3GmxPgzNe3mqVaRVYyk96GBvRnSD/pW+3xsWN3m+My442oGa7HH310zNnIatprSan/5Zf/bTzlU982YxP6HFBQTjSVt37jY1xsxOdzy7q8GauaZrLRcZXro6M+duwHnSLreunSeeJty5r84YefrAF71cQ2F1FnfT/5ZDH/TwOgruh7woTntdOPPz6pV29DA/ozpJ811NS33/6gSWOf2293jEZSUvKtR0Gb4QO//rrCp75txib0OaCghGv+5Zt1UKfes+Fjy2bgFGstXZCqUJ9bbnnu3nv3P//8pzpvxsKmn8Rd3962vHDha+ZTkXV7iUvft/jTnw6p5OGHD/PmBDjz9T1y5C55TbIwk96GBvRnSL8q6HvDBse4Jf/5z3c+9W0zNqHPbzjNtUfStA7KWXz+b9lZ35Wqj4Rr/lHR669//uij7+uzjo2+vW1ZtTVjvFhj57rr+x//cPSuWLfuAMAZ3vdtPoNPnOj4pO9taEB/hvSrgr5Nz4AapD71bTM2oU99W5U3/R7z5+81o6YY8fm/ZWd9V6o+xsjvvHPyW4TPP//OWd+mp/vJJ4utH+N43PKcOa+Y8lmzXjb3C5nOHGd9m49Ed9zxKm9OgDqh74ceOvSzlQqdm9XuQwP6HNLPf32rua2FH3rosLNGfX516W1sQn/uL3zvva9N/8nBg2U6NHPtWbnyzUpt2VnflaqPMe9XX32/bl3Rnj2fmSfe6pPR+dSknC7Lmw5xj1tWo/vTT4+bp0bGLy09bs6zdfZGjXpWQtfFmHcmQF3Rtzx79KjjbW/6FrwNDehzSD//9V1Q8JkR6A8//CSJe2u3ukx6G5vQH31PmPD8669/fvz4jwcOOG5wNDe9WPeo+LllF31Xqj46pTpYnbenny7RWmYVc8Ll5Zde+sx8FWxuTPS2ZTWrdck0N8Dk5b3r0nnyyCNH6DkBqHO/ulQDUJVRM9z5jhSPQwNWc0g/S21miEGXHnZ/8Dg2oU+su/2svhT3//9QtS37v5auf9b5VCvbZSwXfcQx/Vf2W/55tMUXre5vCy0p3b/4YilvS4C6pW+hdp9aiGfqDym3bfvwP//57vnnP1U713xz+MwzJWfSa1GfCXbu/MT6T6QAUIf0bVrWv/Yp2779oyNHjlrdLDXGypVv7t796UcfffPNNz988ME3+pxxhpmuBp47APTNeN8AAOgbfQMAoG8AAPSNvgEA0Hfl9U0IIcQ+gahvpaysrLi4uKioqKCgYMeOHY8QQgg5NXKjDClPypZyZqDo+9ixY6WlpbqkFBYWqn47CSGEnBq5UYaUJ2VLOTNQ9F1eXq7PAiUlJaqZri17CSGEnBq5UYaUJ2VLOZO+b0IIqR0pLi5Wu1vuVtO7oqIiUPS9+f3NAADgDfQNAIC+0TcAQA3qO0D7vnluAADs9R2Id56gbwAAn/oOxPu+0TcAgE99B+iP5nluAADQNwAA+kbfAADoG30DAKBvAAD0jb4BANA3+gYAQN8AAIC+AQDQN/oGAEDf6BsAAH0DAKBv9F19Vr6wctGORTn7cnjxAQD63jxpw6TEmYmG5MXJGfdkbDy4MTDP+GXXXaaju/kPN/PiAwD0fdKJ9ULqBdcLNv/BM6ptVG5hbhXOyJo31sx7Yt6yXcvQNwCg7xrS94g7R2x4d0P6pvSgoCBNpq5KrcIZ6T26t9ZNmJqAvgEAfdecvs3keRedp8nhdwzX4/hJ8Rd2vXBy/uTEWYmt2reauXWmWUZyb3dFu4jIiDYXt7lh8g3yvgrH54xXidZt2rKp1lqxe4XNwoa03LSOV3VsHNVY7f3YfrFWubdV0DcAoG/P+l68c7FpfU97YJo1K+bSmKDgoKiYqBkPz1DhwPSBKmzYpOHgKYPldD2WrPMP50vusq0m23VrFz8xPuvVLJuFNWtQxiBNBtcLjkuI65far8OVHUx9bFZB3wCAvl31rVZw52s7h4SG6HHnnp3zj/yiyxYXtFi1Z5VZWA9MF/mcx+ZocuPBjWeHn63JtLVp7p0nNgtbsyaun+hcGfvto28AQN+u+m7QqEFkm8hOV3dKWpCUtz/vlM6K5b/ocsq9U1QSGhZq3Z0i6atkQNoAd33bLDz1vqmOWWeHrn9nvXNl7LePvgEAfXvt+7b/qnBS3iTTs2Ga56LbwG4q6XNLH3d92yxsZuma4XKTov320TcAoO8q6nvp00vNzYVLnlpiSpq2bKrJ0ctG63H/sf31uP+4/j4Xtmbd9uBtznu03z76BgD0XUV9i67xXc3XidMemGaa201bNV1XtE6zVKLJZtHN0jelm68ubRY2syKaRyTOTMzYkqE2u+m0sVkFfQMA+q66vnMLc3sm9awXUk+zgoKDLupx0bJnTv5OZ9OhTd0HdzdfNt66+Vb7hTWrV3Iv82Wpw+OREeYGQZtV0DcAoO/qIlOv2L3C+SZuCzWirTtVfC5sZq19e63/2wcAQN8AAOi79uvb9C9DYMKzA4C+PZO6OrXH0B7m8Z3b7kycmTj+7vFmMv9I/tzH5w5MH3jZdZf1TembtCDJecWFTy4ccvuQ7oO7x90Yd9OMm6w7Rk7eCPjzcIZaxrlQWxizYgwvoEqRsSVDJ9m9lwkA6rS+J6yboLVGLR1lJkcuGqlJ8yt2udt8YRh2TliHuA7hEeFBQUHWioMyBgXXCxbnX3J+686tg4KDQkJDhs4e6vLlZ1TbKOef5zRq1qhV+1Zn2KuhyqMt+rni6pdX6yno0reLdUc8ANR1fa/as0peaBvb1owr4qLvxTsXm59HmhsBtczCv59sSo/LHqdZ4Y3D1TY3Jbc/dLvzbSeWvhU1289sfVd5tEX/V0xenKwl9Zf3HgD6dpAwLcHl5zPO+l7y1BJzA9/87fNd7gyRha2xCZ3b4yo8t/W5zvrW6ooZ8apS+q7skIRmiMSZW2cmzkyM7hB9weUXZGzJyNufp4tH8/Obdx/c3WrkWoMpDpszLLpjtOrj3Ck0Pmd83I1xLdu1VLnW1TXMvlbeRlt0Rq1m7SKmS4xW7HRNpwV/W2CzoscD1znXYpFtImmAA6BvB/KaVsnem+1R36J1p9aaDKkfIidaw6Esf265aVa7qGrhkwtNudmg0fd1469zOP28c03XrZ/6rvKQhLK2diHN6XGjcxtd0vuSqJioBo0aOH8IsAZTlD0119TZ6u6/fMDlQu3cnkk9Va4t2NfK42iLLpifpLbv3l7V1sedsIZhuYW5Hlf0duBCNXGM5/XoHN5+AHVd3xsPblTTODwi3LnQRd8StBkE3Iw+aLpKzJhTalOrSejSk2uWnP2X2ZYlc/blGEldO/JaP/VdnSEJZXO1x1UTM/itGS9FzXA91qXIWd9q4WpJqb/bDd2MW12bzIfzdZ3QdszVyFutfPaB3PXiXeZLAvOPOnsl99LC5vtbb8M0uu/CcQ0Y57gGpGSm8PYDqOv6znolS8tHd4y20bex5LA5w+o3qG+GA1z69FJJ3Gh6zZtrnNdd+cJK50FLjCXXvrV20Y5F5geWU++f6o++qzMkYfrGdDMrvHG4Ju9+/W6rF6hlu5Yef8Apk5pf8Ft36Y1aOqrH0B6OQXTrh1gfMrzVyqe+M+5xXDzU4o67MU6Yi5ma2+4r2uxCDL9juOY6fzkMAHVU32o7q60nrdjr27DsmWUSnGbp47+sbTRt/QseZ09pm3kH8pz1rceJMxP1uEmLJtqdT31XZ0jCKuh7bNZY072jx2vfXms+bcT2i02YlqCPJpa+vdXKp77TN6Wbq078pPiB6QMN2tpmL8M0etyF6JvSV3PHZY/j7QdA3/dm033s/DN3b/oWXa93jCd15ZArTQexHl/6u0stk+pi0CGugwqtW8id9a25bWPbGukbfWe9mjX9j9OtrzSdqc6QhFXQt+nNUFvbUm3HqzqaWc2im1n69larzW6jLbpgfVVg+pRsVrTZhfVRY94T83j7AaDvzcPmDtMqajU7/6xGJZ2u7qTH0o0aofrMrlZ20sIk0wGSluvoaM4syDR+lNOnPTDt1s23mi/WGp3byPoi1FnfxqGhZ4da+jb3m2sjHitW5SEJ/de3mttq7Vr9QuZ+x/nb5+tx46jG43PGXzHoiqDgIOvyYFMr99EWXdAlTQtEtokccvuQyfmT1a43twB6G6bRfRf6QBMRGXHm3XMJgL6rqO+cfTmmM9r6tN7nlj5WC1pNY/NNmomE6HynoNrssf1jrQXqhdSLS4jLfi3b5Wc7lr6t3ltnfTdp0cRjxao8JKH/+lZtTeNdFxVJ3Nr1tSOvDakfoo33HtX7+gnXmwqY8+OtVu6jLbqw/p31A9IGhIaFmhV1zk2HicdhGj3u4qYZN9FzAoC+T0ENwKCgoKsSrxqYPlCtwoZNGjrfRSe/rHxh5ZzH5uhzvXXjoDMqXPC3BfKjx+5aeyRHOdS+d/7XGJLQ6jzJP5Kvo3OvuRxq7VQfJswdIz5r5T7aovvd39rdmjfW+FzRZRdaS+o33VYAgL5/Qe2+dle0Mz0bYeeExU+Mt36E+etx57Y7oztGm/9qX8PUuqHDM7Zk9BnTx+PlEwDqtL7N3YFqG6rVWWNnUI3QKjTYTwsD0gbEdImxulkCn9/qRAGgb8b7BgBA3+gbAAB9AwCgb/QNAIC+q6FvQggh9glEfStlZWXFxcVFRUUFBQU7dux4hBBCyKmRG2VIeVK2lDMDRd/Hjh0rLS3VJaWwsFD120kIIeTUyI0ypDwpW8qZgaLv8vJyfRYoKSlRzXRt2UsIIeTUyI0ypDwpW8qZ9H0TQkjtSHFxsdrdcrea3hUVFdx5AgBQO+48Qd8AAOgbfQMA1JS+A7Tvm+cGAMBe34F45wn6BgDwqe9AvO8bfQMAMOYJAAD6Rt8AAOgbfQMAoG8AAPSNvgEA0Df6BgBA3wAAgL4BANA3+gYAQN/oGwAAfQMAoG/0DQCAvtE3AAD69sTNf7g5cWaiRzSLJx4A0HeA6rvNxW3qN6gvQsNCzf/01ANT0rpz61r6bK15Y828J+Yt27WMFy4AnPmdJ1mvZhl9Z72SVdufrd6je+tAEqYm8MIFgLqr7/hJ8Rd2vXBy/uTEWYmt2reauXWmCsfnjI+7Ma5lu5Yq6ZvSd/HOxe7Lp9yVEtMlpl23dnpszV371lptp3PPzhGREWr4Jy9Odllr2Jxh0R2jtdmkBUnO1UhdldruinZmrRsm37Dh3Q3eqqe6aTEdSNOWTTVrxe4VvHwB0Hdd1Pdl112mwphLY4KCg6JiomY8PEOFlw+4XEi+PZN6au4lvS9xWV7ePDv87OgO0XocHhGedyDPzL3mv64xy49eNrpfaj/L0dZeZF7txdRk/N3jzdyB6QM12bBJw8FTBsvRZvv5h/M9Vk8Gl+JVqCtH/MR4HRcvXwD0XXf13eKCFqv2rHJfSw6VVYOCgrL3Zjsv3/z85qak0bmNNGmkL6RUTQ6/Y7jLdsxaHa/qqGa1ttnthm6abN+9vWZpv8H1gjU557E5mtx4cKMuDJpMW5vmrXp0ngAA+j7px5uXn3IXyrqidaOWjuoxtEfnazuH1A/RAlYfhVlejWszqXaxJjO2ZJjJW1beYvaiBnLq6tRNhzadspf/u9dlzIoxmoxoHqHHU+6dYr5QlbjNXO1UJQPSBnirHvoGAPTtKlZH//Xba8+76DwVxvaLTZiWEB4R7q5va3kXfYtZf57VNrat2VfX+K4e1xqbNVaT5553rh5Pyptkek7yj+Sbud0GOtrmfW7p47F66BsA0LdnfadvSjcdHWayWXSzSun75EY2OjYSFBSU+VKm+1q9kntpUq1sPV769FJTsSVPLTFzm7ZsajXwPeq7/9j+Kuw/rj8vXABA37/4cf72+SppHNV4fM74KwZdERQc5NxbYq9veXnE/BHz/jpvXPY4lddvUH9d0TprLTW31dYeNmeYyjV56+ZbzVpqpJuvK6c9MM20rJu2auq8oou+tZgKdV3RlYavLgHQN/r+pfDakdeG1A+RuHuP6n39hOvNiqZv2l7fnXt2Nl88avWLe108/U/TnfcSlxBnWtahZ4dK4tbucgtzeyb1rBdSz9FgDw66qMdFy55ZZlO9TYc2dR/c3ezIugYAAPpmzJOTSl379lrzOHtvds6+HD9XzD+Sn/lSpmk7u18kNHflCyutbyldpLxi9wrrjm+f5O3P83i3DACgb4asOm14bEQDAKBvV1wav785A9IGxHSJSd+YzkstYJ8jAPT92+s7dXVqj6E9aubE+Tmi4eJ/LFaJahXbL7b36N5DZw+d9edZjrsGN0yylk9enJxxT4bHfhUXzFqz/zLbKsl+LdtsxGeVfFa4alWqAhlbMroP7m71UAFAXdf3hHUTtNaopaNq5sT5HNEw/0i+mt7md5XNz2/e8aqO5zQ9R4+vuukqq1OlXkg9s4AS1TYqtzDXn66YIbcPsUoW7VhkVtfu7Kvks8JVq5Izfg6IuPrl1WHnhHXp28W64R0A6q6+V+1ZJSO0jW1rBgypSbzd2aImrQpVK+d7w1fsXrHgbwssV464c8SGdzekb0oPCnLcpJi6KrU6+vZZJX9uxalslar2qyK17rWkNbAXANRdfSdMS9Aqtz14m5ms1GiC0x6YpoWlLasHRpOWWZIWJsX2j62svjcd2mR+tKkK2IjY2qn5taf7kCm/ib59Vkn7SlqQFNMlpnFU407XdDIXJG8DIqblpumTh5ZUWz62X6x1frRYZJtIGuAAdV3fzc9vrlVchpfyczTBlS+s1GR0h2gzKddo8oLLLzCT0R2j7fvTPdpw+bPLTaG3YV2dXakLiWnq6kLij757Jfea+/hcw/i7x/8a+ravkvnxZ/vu7QdPGayPF2ENw3ILcz0OiDgoY5BKgusFxyXE9Uvt1+HKDtZGdP4dw3U9Ooc3IUDd1ffGgxulabV2XUzk/2iCLS5soeUzX8pc88YauSb07FD9XfPmGslX5RPWTaisvqfeN9X8dN7bt3/WSISOsbFCHWNjde7Z2WdT1KzlMadL3z6rdNeLd+nkCHNHvBkGYMyKMe6dJ9aQihPXT/RwDRjnuAakZKbwJgSou/qWhhzN547Rrndb+z2aoBqGDpXclaJP+vVC6l33++s0mb4pfeSikRKQ/dd3Hm0457E5pjD7tWwbETdo1CCyTWSnqzslLUjK25/n513kp7S+c05z69tnlTLuyXD06TcMi7sxTpgWt5rb7vo21zBdC9e/s959O8PvGK65Q2cP5U0IUHf1venQJklWQrH5sYz9aIJGNN1u6CYfdbqmkz7RO0b+G9NHzc+LelxUha8u1TI1he5jWnnsaK7Uj4Bqpu/bG2Zgr9Cw0PhJ8QPTBxom5U1y17cZUlHXA48fQfqm9NXccdnjeBMC1Om+b/OvaqyuksqOJqjmodrjcnp443C1OnU90MWgaaumaon71Jk3G5q+XV0zPN7g7M2V2tr0P063/gtEAOp7+XMnu/Wdbz937hO3BkS0hlS0vlJ2xgxuPu+JebwJAeq0vofNHeZo6t6T4U3f9qMJbv55zCnjGulJk2qkm0mfdzF7s6GuDboGqDyyTeSI+SPUDFclL/3dpaqbjSvN3eu6igSsvkWPoT3Mcakmk/Mn69OMuVHHfUBEM6RiRPOIxJmJOgNqmJsOmbwDeRGREbro8g4EqOv6ztmX06hZI+nA4+iABpvRBK2u2JbtWlr3C5rfrVT5vm+RWZCpmli/glFbvnXn1jfNuMmnvpu0aBLI+taHlQFpA6yf/+jMmw4T9wERcwtzeyX3Ml+EOjweGWFG5tJJoOcEAH1vtm7fDgoKUgvXZpkqjyZYHXSFWPLUkoVPLrT+r7E9urTEJcQF/kvHjKG45o01LuXuAyKaIRWtM6+1pP4rh1zJ2w8AfZ9ELT619Wr183HntjujO0b7vAG8VpOxJaPPmD7+3GkDAHVF36apW6ufDzVma/shnPHPEQD6rhPjfQMAoG8AAEDfAADoG30DAKBv9A0AgL4BANB3zeubEEKIfQJR30pZWVlxcXFRUVFBQcGOHTseIYQQcmrkRhlSnpQt5cxA0fexY8dKS0t1SSksLFT9dhJCCDk1cqMMKU/KlnJmoOi7vLxcnwVKSkpUM11b9hJCCDk1cqMMKU/KlnJmoOi7oqJCFxPVSVcVfS44TAgh5NTIjTKkPClbypmBou8TJ06oNrqeqFplZWVfEkIIOTVyowwpT8qWcmag6JsQQsivGvRNCCHomxBCCPomhBCCvgkhBH0TQghB34QQQtA3IYSgb0IIIeibEEII+iaEEIK+CSEEfRNCCEHfhBBC0DchhKBvQggh6JsQQgj6JoQQ9M1JIYQQ9E0IIQR9E0IIQd+EEIK+CSGEoG9CCCHomxBC0DchhJDA1jchhJBaFPRNCCHomxBCSE3l/wOElkIjUdGBzgAAAABJRU5ErkJggg==%}

#####Transport

Transport层提供了一个抽象的网络读写接口,解耦网络层和其他层之间的关系(比如序列化/反序列化)
Transport层接口如下

- open

- close

- read

- write

- flush

在Transport层上thrift还定义了ServerTransport层来提供接受或者创建transport对象的功能。顾名思义,该层用于为进入的链接创建新的
transport对象,其包含接口如下



- open

- listen

- accept

- close

对于thrift支持的语言来说,下面的接口都是可用的

- file: read/write to/from a file on disk

- http: as the name suggests

#####Protocol

负责内存中的数据结构和网络协议的转化

py writeMessageBegin(name, type, seq)

writeMessageEnd()
writeStructBegin(name)
writeStructEnd()
writeFieldBegin(name, type, id)
writeFieldEnd()
writeFieldStop()
writeMapBegin(ktype, vtype, size)
writeMapEnd()
writeListBegin(etype, size)
writeListEnd()
writeSetBegin(etype, size)
writeSetEnd()
writeBool(bool)
writeByte(byte)
writeI16(i16)
writeI32(i32)
writeI64(i64)
writeDouble(double)

writeString(string)

name, type, seq = readMessageBegin()
readMessageEnd()
name = readStructBegin()
readStructEnd()
name, type, id = readFieldBegin()
readFieldEnd()
k, v, size = readMapBegin()
readMapEnd()
etype, size = readListBegin()
readListEnd()
etype, size = readSetBegin()
readSetEnd()
bool = readBool()
byte = readByte()
i16 = readI16()
i32 = readI32()
i64 = readI64()
double = readDouble()

string = readString()

1
2
3
4
5
6
7
8
9
10
thrift的协议格式是流式的,不需要应用层进行显式的分页,因此对于thrift格式来说,复杂数据结构的大小没必要事先定义,比如string的长度
以及list内的个数。thrift支持三种编码方式

- binary: 简单的二进制编码
- compact: 压缩编码,参见[THRIFT-110](https://issues.apache.org/jira/browse/THRIFT-110)
- json:

#####Processor

Processor封装了从流中读取和写入的函数,读取和写入的都是Protocol对象,简单例子如下

java interface TProcessor {

    bool process(TProtocol in, TProtocol out) throws TException

}

1
2
3
4
5
6
7
8
9
10
11
12
由特定代码生成的服务中的Processor,在流中读取数据,将结构委托给相应的处理程序,然后将处理结果的对象写入流中

#####Server

一个服务具有上面描述的所有性质

- 创建一个transport
- 为每个transport创建一个protocol
- 根据读取/写入protocol创建processor
- 等待链接接入并进行处理

IDL例子

namespace cpp thrift.example namespace java thrift.example

enum TweetType {

TWEET,
RETWEET = 2,
DM = 0xa,
REPLY

}

struct Location { 1: required double latitude; 2: required double longitude; }

struct Tweet { 1: required i32 userId; 2: required string userName; 3: required string text; 4: optional Location loc; 5: optional TweetType tweetType = TweetType.TWEET; 16: optional string language = “english”; }

typedef list TweetList

struct TweetSearchResult { 1: TweetList tweets; }

const i32 MAX_RESULTS = 100;

service Twitter {

void ping(),
     bool postTweet(1:Tweet tweet);
TweetSearchResult searchTweets(1:string query);
oneway void zip()

} “`

备注

thrift序列化属于传值调用,它将IDL中的值全部分配空间,而不是给未赋值的元素设置null。这样可能会导致内存占用多。service定义的函数在动态语言里 无法返回null,因此需要空值时首先初始化一个空的结构然后进行返回。对于transport可能会因为调用不同参数的同名函数导致彼此通讯异常。比如 初始版本的service含有postTweet(1: Tweet tweet), 但是新版本中转变为postTweet(1: Tweet tweet, 2: string group),则老版本中client 端调用该函数,而server端调用新版本进行解析则会导致新定义的参数为空。

thrift可以保持前向和后向的兼容性,可以在老的message中添加新的字段不会影响彼此解析,但是需要注意的是

  • 不要修改tag值
  • 新添加的字段定义为optional
  • 不再需要的字段可以被移除,只要其tag值不再使用
  • 可以修改默认值,但是发送端是无法将修改的默认值通过网络传输给接收端的

资源

pt包含部分thrift序列化方法 Thrift: The Missing Guide这是一篇教程文档

Log4j使用

| Comments

介绍log4j使用,主要转载Log4j使用指南

概述

本文档是针对Log4j日志工具的使用指南。包括:日志介绍、日志工具介绍、Log4j基本使用、Log4j的高级使用、Spring与log4j的集成等。并进行了举例说明。

介绍

日志工具支持级别配置、输出格式配置、输出源配置等功能。工具包括:logger4j、Commons Logging、Simple Log 、MonoLog

Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码

log4j的好处在于:

  1. 通过修改配置文件,就可以决定log信息的目的地——控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等

  2. 通过修改配置文件,可以定义每一条日志信息的级别,从而控制是否输出。在系统开发阶段可以打印详细的log信息以跟踪系统运行情况,而在系统稳定后可以关闭log输出,从而在能跟踪系统运行情况的同时,又减少了垃圾代码(System.out.println(……)等)。

  3. 使用log4j,需要整个系统有一个统一的log机制,有利于系统的规划。

此外,通过Log4j其他语言接口,您可以在C、C++、.Net、PL/SQL程序中使用Log4j,其语法和用法与在Java程序中一样,使得多语言分布式系统得到一个统一一致的日志组件模块。而且,通过使用各种第三方扩展,您可以很方便地将Log4j集成到J2EE、JINI甚至是SNMP应用中。

Log4j基本配置

Log4j由三个重要的组件构成:Loggers,Appenders和Layouts,分别表示:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。支持key=value格式设置或xml格式设置

  • 日志信息的优先级从高到低有FATAL、ERROR、WARN、INFO、DEBUG,分别用来指定这条日志信息的重要程度
  • 日志信息的输出目的地指定了日志将打印到控制台还是文件中
  • 输出格式则控制了日志信息的显示内容

日志信息的优先级

Log4j划分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。 Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。

假如在一个级别为q的Logger中发生一个级别为p的日志请求,如果p>=q,那么请求将被启用。这是Log4j的核心原则。 比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

输出源的使用

有选择的能用或者禁用日志请求仅仅是Log4j的一部分功能。Log4j允许日志请求被输出到多个输出源。用Log4j的话说,一个输出源被称做一个Appender。 Appender包括console(控制台), files(文件), GUI components(图形的组件), remote socket servers(socket 服务), JMS(java信息服务), NT Event Loggers(NT的事件日志), and remote UNIX Syslog daemons(远程UNIX的后台日志服务)。它也可以做到异步记录。

一个logger可以设置超过一个的appender。 用addAppender 方法添加一个appender到一个给定的logger。对于一个给定的logger它每个生效的日志请求都被转发到该logger所有的appender上和该logger的父辈logger的appender上。

ConsoleAppender

如果使用ConsoleAppender,那么log信息将写到Console。效果等同于直接把信息打印到System.out上了。

FileAppender

使用FileAppender,那么log信息将写到指定的文件中。这应该是比较经常使用到的情况。相应地,在配置文件中应该指定log输出的文件名。如下配置指定了log文件名为dglog.txt

1
log4j.appender.A2.File=dglog.txt

注意将A2替换为具体配置中Appender的别名

DailyRollingAppender

使用FileAppender可以将log信息输出到文件中,但是如果文件太大了读起来就不方便了。这时就可以使用DailyRollingAppender。DailyRollingAppender可以把Log信息输出到按照日期来区分的文件中。配置文件就会每天产生一个log文件,每个log文件只记录当天的log信息:

1
2
3
4
5
6
7
8
9
log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender

log4j.appender.A2.file=dglog

log4j.appender.A2.DatePattern='.'yyyy-MM-dd

log4j.appender.A2.layout=org.apache.log4j.PatternLayout

log4j.appender.A2.layout.ConversionPattern= %5r %-5p %c{2} - %m%n 

RollingFileAppender

文件大小到达指定尺寸的时候产生一个新的文件。

1
2
3
4
5
6
7
8
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File= ../logs/dglog.log
# Control the maximum log file size
log4j.appender.R.MaxFileSize=100KB
# Archive log files (one backup file here)
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

这个配置文件指定了输出源R,是一个轮转日志文件。最大的文件是100KB,当一个日志文件达到最大尺寸时,Log4J会自动把example.log重命名为dglog.log.1,然后重建一个新的dglog.log文件,依次轮转。

WriterAppender

将日志信息以流格式发送到任意指定的地方。

Layout的配置

Layout指定了log信息输出的样式

布局样式

1
2
3
4
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

格式

1
2
3
4
5
6
7
8
%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为"rn",Unix平台为"n"
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(Test Log4.java:10) 

例子

例子1:显示日期和log信息

1
2
3
4
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %m%n
打印的信息是:
2002-11-12 11:49:42,866 SELECT * FROM Role WHERE 1=1 order by createDate desc

例子2:显示日期,log发生地方和log信息

1
2
3
4
5
6
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %l "#" %m%n
2002-11-12 11:51:46,313 cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) "#"
SELECT * FROM Role WHERE 1=1 order by createDate desc
  
例子3:显示log级别,时间,调用方法,log信息

log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n log信息: [DEBUG] 2002-11-12 12:00:57,376 method:cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) SELECT * FROM Role WHERE 1=1 order by createDate desc

1
2

Properties配置文件实例

log4j.rootLogger=DEBUG

将DAO层log记录到DAOLog,allLog中

log4j.logger.DAOLog=DEBUG,A2,A4

将逻辑层log记录到BusinessLog,allLog中

log4j.logger.Businesslog=DEBUG,A3,A4

A1–打印到屏幕上

log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-5p [%t] %37c %3x - %m%n

A2–打印到文件DAOLog中–专门为DAO层服务

log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.file=DAOLog log4j.appender.A2.DatePattern=’.’yyyy-MM-dd log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

A3–打印到文件BusinessLog中–专门记录逻辑处理层服务log信息

log4j.appender.A3=org.apache.log4j.DailyRollingFileAppender log4j.appender.A3.file=BusinessLog log4j.appender.A3.DatePattern=’.’yyyy-MM-dd log4j.appender.A3.layout=org.apache.log4j.PatternLayout log4j.appender.A3.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

A4–打印到文件alllog中–记录所有log信息

log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender log4j.appender.A4.file=alllog log4j.appender.A4.DatePattern=’.’yyyy-MM-dd log4j.appender.A4.layout=org.apache.log4j.PatternLayout log4j.appender.A4.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

1
2
3
4
5
6
7
8
9
10
11
12
13
14

##Log4j高级配置

###配置记录日志的包路径

配置Log4j.logger.com.int97=debug, 只有包为com.int97中代码的debug信息被输出到指定的输出源。

###支持日志级别继承功能

如果log4j.rootLogger=debug,其他logger默认级别为debug。可以通过配置log4j.additivity.XXX=ture/false来打开或关闭继承功能;若为 false,表示Logger 的 appender 不继承它的父Logger; 若为true,则继承,这样就兼有自身的设定和父Logger的设定。

###为不同的 Appender 设置日志输出级别

通常所有级别的输出都是放在一个文件里的,如果日志输出的级别是DEBUG级别,查找异常不是很方便。Log4j提供仅保存异常的日志功能,只需要在配置中修改Appender的Threshold 就能实现,比如下面的例子:

set log levels

log4j.rootLogger = debug , stdout , D , E

输出到控制台

log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n

输出到日志文件

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志 log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

保存异常信息到单独文件

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = logs/error.log ## 异常日志文件名 log4j.appender.D.Append = true log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!! log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

1
2

###Xml格式配置文件实例

html

<?xml version=”1.0” encoding=”GB2312”?>

<!DOCTYPE log4j:configuration SYSTEM “log4j.dtd”>

<log4j:configuration xmlns:log4j=”http://jakarta.apache.org/log4j/”>

   <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">

          <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d %-5p - [%C{1}] %m%n"/>

          </layout>

   </appender>

          <param name="File" value="${myApp.root}/WEB-INF/logs/myApp.log"/>

          <param name="Append" value="true"/>

          <param name="MaxBackupIndex" value="3"/>

          <param name="MaxFileSize" value="2MB" />

          <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

          </layout>

   </appender>



   <appender name="moduleA.log"   class="org.apache.log4j.RollingFileAppender">  

    <param name="Append" value="true"   />  

    <param name="File" value="${myApp.root}/WEB-INF/logs/moduleA.log"   />  

    <param name="MaxFileSize" value="2MB"/>  

    <param name="MaxBackupIndex" value="10"   />  

    <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

          </layout>

          <filter class="org.apache.log4j.varia.StringMatchFilter">

                 <param name="StringToMatch" value=" MODULE_A _TASK_" />

                 <param name="AcceptOnMatch" value="true" />

          </filter>

</appender>



<appender name="moduleB.log"   class="org.apache.log4j.RollingFileAppender">  

    <param name="Append" value="true"   />  

    <param name="File" value="${myApp.root}/WEB-INF/logs/moduleB.log"   />  

    <param name="MaxFileSize" value="2MB"/>  

    <param name="MaxBackupIndex" value="10"   />  

    <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

          </layout>

          <filter class="org.apache.log4j.varia.StringMatchFilter">

                 <param name="StringToMatch" value="MODULE_B_TASK_" />

                 <param name="AcceptOnMatch" value="true" />

          </filter>

</appender>



<logger name="com.levinsoft.myApp.task.FileTaskThread">

       <level value="DEBUG"/>

       <appender-ref ref="moduleA.log"/>

       <appender-ref ref="moduleB.log"/>

</logger>





<appender name="authorization.log.debug"   class="org.apache.log4j.RollingFileAppender">  

    <param name="Append" value="true"   />  

    <param name="File" value="${myApp.root}/WEB-INF/logs/authorization_debug.log"   />  

    <param name="MaxFileSize" value="2MB"/>  

    <param name="MaxBackupIndex" value="3"   />  

    <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

          </layout>

          <filter class="org.apache.log4j.varia.LevelRangeFilter">

                 <param name="LevelMin" value="debug" />

                 <param name="LevelMax" value="debug" />

                 <param name="AcceptOnMatch" value="true" />

          </filter>



</appender>



<appender name="authorization.log.error"   class="org.apache.log4j.RollingFileAppender">  

    <param name="Append" value="true"   />  

    <param name="File" value="${myApp.root}/WEB-INF/logs/authorization_error.log"   />  

    <param name="MaxFileSize" value="2MB"/>  

    <param name="MaxBackupIndex" value="3"   />  

    <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

          </layout>



           <filter class="org.apache.log4j.varia.LevelRangeFilter">

                 <param name="LevelMin" value="error" />

                 <param name="LevelMax" value="error" />

                 <param name="AcceptOnMatch" value="true" />

          </filter>



</appender>



<logger name="com.levinsoft.myApp.authorization">

       <level value="DEBUG"/>

       <appender-ref ref="authorization.log.debug"/>

       <appender-ref ref="authorization.log.error"/>

</logger>



   <logger name="com.levinsoft.qframe.taglib.CollectionTag">

          <level value="WARN"/>

   </logger>



   <appender name="moduleC_error.log"   class="org.apache.log4j.RollingFileAppender">  

    <param name="Append" value="true"   />  

    <param name="File" value="${myApp.root}/WEB-INF/logs/moduleC_error.log"   />  

    <param name="MaxFileSize" value="2MB"/>  

    <param name="MaxBackupIndex" value="10"   />  

    <layout class="org.apache.log4j.PatternLayout">

                 <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

          </layout>

           <filter class="org.apache.log4j.varia.LevelRangeFilter">

                 <param name="LevelMin" value="error" />

                 <param name="LevelMax" value="error" />

                 <param name="AcceptOnMatch" value="true" />

          </filter>

</appender>



<logger name="com.levinsoft.myApp.search.ModuleC">

          <level value="ERROR"/>

          <appender-ref ref="moduleC_error.log"/>

   </logger>



   <logger name="com.levinsoft">

          <level value="DEBUG"/>

          <!-- <appender-ref ref="myApp.file.log"/> -->

   </logger>



   <root>

          <level value="WARN"/>

          <appender-ref ref="STDOUT"/>

          <appender-ref ref="myApp.file.log"/>

          <!-- activate to log in files -->

          <!--<appender-ref ref="DAILY"/>-->

          <!--<appender-ref ref="HTML"/>-->

   </root>

</log4j:configuration>

1
2
3
4
5
6
7
8

##Spring对log4j的支持

Log4jConfigurer、 Log4jConfigListener、Log4jConfigServlet对dom4j进行配置或封装。org.springframework.web.util 还包括了对其他工具类的封装。

###log4j配置文件放置路径

在web.xml文件中,可以指定log4j配置文件的放置位置。缺省情况下,系统在WEB-INF/classes目录下查找。也可以在web.xml文件中指定一个位置,例如:系统将自动的进行加载。

xml

          <param-name>log4jConfigLocation</param-name>

          <param-value>/WEB-INF/classes/log4j.xml</param-value>

1
2
3
4

###log4j文件中引用web.xml中的属性

在使用Spring的应用中,在web.xml可以配置spring指定的系统属性,log4j配置文件可以引用系统属性。

          <param-name>webAppRootKey</param-name>

          <param-value>usboss.root</param-value>

   </context-param>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

```
<appender name="myApp.file.log" class="org.apache.log4j.RollingFileAppender">

              <!-- ${myApp.root}变量仅适用于Spring的配置 -->

              <param name="File" value="${myapp.root}/WEB-INF/logs/myApp.log"/>

              <param name="Append" value="true"/>

              <param name="MaxBackupIndex" value="3"/>

              <param name="MaxFileSize" value="2MB" />

              <layout class="org.apache.log4j.PatternLayout">

                     <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

              </layout>

       </appender>

java使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.apache.log4j.Logger;
 import org.apache.log4j.PropertyConfigurator;

 public class Test {

   public static void main(String[] args) {
     //Get an instance of the myLogger   
     Logger myLogger = Logger.getLogger("myLogger");

     //Get an instance of the childLogger   
     Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");
     //Load the proerties using the PropertyConfigurator   
     PropertyConfigurator.configure("log4j.properties");

     //Log Messages using the Parent Logger   
     myLogger.debug("Thie is a log message from the " + myLogger.getName());
     myLogger.info("Thie is a log message from the " + myLogger.getName());
     myLogger.warn("Thie is a log message from the " +  myLogger.getName());
     myLogger.error("Thie is a log message from the " + myLogger.getName());
     myLogger.fatal("Thie is a log message from the " + myLogger.getName());

     mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());
     mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());
     mySonLogger.warn("Thie is a log message from the " +  mySonLogger.getName());
     mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());
     mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());
   }
}

程序运行结果为:

    WARN - Thie is a log message from the myLogger
    ERROR - Thie is a log message from the myLogger
    FATAL - Thie is a log message from the myLogger
    WARN - Thie is a log message from the myLogger.mySonLogger
    ERROR - Thie is a log message from the myLogger.mySonLogger
    FATAL - Thie is a log message from the myLogger.mySonLogger

    另在Test.class所在的目录下看到一个log.txt文件,内容如下:

    WARN - Thie is a log message from the myLogger.mySonLogger
    ERROR - Thie is a log message from the myLogger.mySonLogger
    FATAL - Thie is a log message from the myLogger.mySonLogger

    如将配置文件log4j.properties中语句

log4j.logger.myLogger.mySonLogger=,file

改为

log4j.logger.myLogger.mySonLogger=,file,console

再次运行程序,结果如下:

    WARN - Thie is a log message from the myLogger
    ERROR - Thie is a log message from the myLogger
    FATAL - Thie is a log message from the myLogger
    WARN - Thie is a log message from the myLogger.mySonLogger
    WARN - Thie is a log message from the myLogger.mySonLogger
    ERROR - Thie is a log message from the myLogger.mySonLogger
    ERROR - Thie is a log message from the myLogger.mySonLogger
    FATAL - Thie is a log message from the myLogger.mySonLogger         
    FATAL - Thie is a log message from the myLogger.mySonLogger

    mySonLogger的日志在控制台上输出了二次,这是因为mySonLogger继承了父类console Appender,
    本身又定义了一个console Appender, 因而有二个console Appender。

Mockito

| Comments

简介

使用

转载自Mockito Java测试框架 使用手册 功能一览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
package com.ailk.ecs.ci;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.verification.Timeout;

public class MockitoTest {

  //1
  //验证模拟的行为
  //一旦创建了模拟对象,Mockito就会记录下此模拟对象的所有行为
  @Test public void test1() {

      //创建模拟的对象
      List mockedList = mock(List.class);

      //使用模拟的对象
      mockedList.add("one");
      mockedList.clear();

      //验证模拟的对象是否被调用过
      verify(mockedList).add("one");
      verify(mockedList).clear();
  }

  //2
  //如何进行打桩
  @Test public void test2() {
      //模拟的classes不一定是接口
      LinkedList mockedList = mock(LinkedList.class);

      //打桩!
      when(mockedList.get(0)).thenReturn("first");
      when(mockedList.get(1)).thenReturn(new RuntimeException());

      //下面的执行结果会打印"first"
      System.out.println(mockedList.get(0));

      //下面的执行结果会跑出 runtime exception
      System.out.println(mockedList.get(1));

      //下面的运行结果会打印 "null" 因为 get(999) 没有进行过打桩
      System.out.println(mockedList.get(999));
  }

  //3
  //参数匹配器(matchers)
  @Test public void test3() {
      //用anyInt()参数匹配器进行打桩
      LinkedList mockedList = mock(LinkedList.class);

      //如果您使用的参数匹配,所有参数都必须提供匹配!!!!
      when(mockedList.get(anyInt())).thenReturn("element");

      //用hamcrest进行打桩(当我们执行 isValid() 方法时,会返回一个自己定义 hamcrest匹配器)
      //when(mockedList.contains(argThat(isValid()))).thenReturn("element");

      //下面的执行结果会打印"element"
      System.out.println(mockedList.get(999));

      //你同样可以以下面形式,进行验证
      verify(mockedList).get(anyInt());

      //下面的写法是错误的
      //verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
      //verify(mock).someMethod(anyInt(), anyString(), "third argument");

  }

  //4
  //验证确切的请求次数 at least x / never
  @Test public void test4() {
      LinkedList mockedList = mock(LinkedList.class);

      mockedList.add("once");

      mockedList.add("twice");
      mockedList.add("twice");

      mockedList.add("three times");
      mockedList.add("three times");
      mockedList.add("three times");

      //下面两种方法是等价的
      //times(1)是默认的,因此可以省略
      verify(mockedList).add("once");
      verify(mockedList, times(1)).add("once");

      //其他一些实用的方法
      verify(mockedList, never()).add("never happened");
      verify(mockedList, atLeastOnce()).add("three times");
      verify(mockedList, atLeast(2)).add("five times");
      verify(mockedList, atMost(5)).add("three times");
  }

  //5
  //void 方法异常的打桩
  @Test public void test5() {
      LinkedList mockedList = mock(LinkedList.class);

      doThrow(new RuntimeException()).when(mockedList).clear();

      //下面会抛出 RuntimeException
      mockedList.clear();
  }

  //6
  //验证调用顺序
  @Test public void test6() {
      //A. 单一的方法是否按照特定的顺序执行
      List singleMock = mock(List.class);

      singleMock.add("was added first");
      singleMock.add("was added second");

      //为 single mock 创建一个 inOrder 验证器
      InOrder inOrder = inOrder(singleMock);

      //开始对执行的顺序进行校验
      inOrder.verify(singleMock).add("was added first");
      inOrder.verify(singleMock).add("was added second");

      //B. 多个模拟的对象的方法是否按照顺序执行
      List firstMock = mock(List.class);
      List secondMock = mock(List.class);

      firstMock.add("was called first");
      secondMock.add("was called second");

      InOrder inOrder2 = inOrder(firstMock, secondMock);

      inOrder2.verify(firstMock).add("was called first");
      inOrder2.verify(secondMock).add("was called second");

      //C. 当然 A + B 的形式也可以混合使用,这里就略掉了

  }

  //7
  //确定模拟对象之间没有相互调用
  @Test public void test7() {
      List mockOne = mock(List.class);
      List mockTwo = mock(List.class);
      List mockThree = mock(List.class);

      mockOne.add("one");
      verify(mockOne).add("one");
      verify(mockOne, never()).add("two");

      verifyZeroInteractions(mockTwo, mockThree);
      //如果这样 mockTwo.add(mockThree) 执行上面的验证时,就会报错了
  }

  //8
  //找到冗余的调用
  @Test public void test8() {
      LinkedList mockedList = mock(LinkedList.class);

      mockedList.add("one");
      mockedList.add("two");

      verify(mockedList).add("one");

      //下面的执行会失败
      verifyNoMoreInteractions(mockedList);
  }

  //9
  //利用 @Mock 注解进行创建模拟对象
  //Important! This needs to be somewhere in the base class or a test runner:

  public class Aclass {
      public Object someMethod(String arg) {
          return null;
      }
  }
  //10
  //连续调用桩
  @Test public void test10() {
      Aclass mock = mock(Aclass.class);
      when(mock.someMethod("some arg"))
          .thenThrow(new RuntimeException())
          .thenReturn("foo");

      try{
          //第一次调用,会抛出 runtime exception
          mock.someMethod("some arg");
      } catch (RuntimeException e) {
          System.out.println("runtime exception");
      }

      //第二次调用,会打印"foo"
      System.out.println(mock.someMethod("some arg"));

      //继续调用,会一直打印"foo"
      System.out.println(mock.someMethod("some arg"));

      //另一种简略的写法
      when(mock.someMethod("some arg"))
          .thenReturn("one", "two", "three");
      System.out.println("1:" + mock.someMethod("some arg"));
      System.out.println("2:" + mock.someMethod("some arg"));
      System.out.println("3:" + mock.someMethod("some arg"));
  }

  //11
  //对回调方法进行打桩
  @Test public void test11(){

      Aclass mock = mock(Aclass.class);
      when(mock.someMethod(anyString())).thenAnswer(new Answer(){
              public Object answer(InvocationOnMock invocation) {
              Object[] args = invocation.getArguments();
              //                Object mock = invocation.getMock();
              return "called with arguments:" + args[0];
              }
              });

      Object a = mock.someMethod("foo");
      //下面将会打印"called with arguments: foo"
      System.out.println(mock.someMethod("foo"));
  }

  //12
  //doThrow()|doAnswer()|doNothing()|doReturn()  主要是用于 void 类型打桩
  @Test public void test12() {
      LinkedList mockedList = mock(LinkedList.class);
      doThrow(new RuntimeException()).when(mockedList).clear();
      //following throws RuntimeException:
      mockedList.clear();
  }

  //13
  //spying调用真正对象
  @Test public void test13() {
      List list = new LinkedList();
      List spy = spy(list);

      //您也可以选择一些方法的存根
      when(spy.size()).thenReturn(100);

      //调用spy的真实方法
      spy.add("one");
      spy.add("two");

      //打印 "one" - list的第一个原素
      System.out.println(spy.get(0));

      //被打桩的size方法,会打印100
      System.out.println(spy.size());

      //您也可以进行验证
      verify(spy).add("one");
      verify(spy).add("two");

  }

  //14
  //更改未进行打桩的默认返回值(Since 1.7)
  //当如下初始化一个mock的时候,如果调用未被打桩,会返回默认值
  //下面的两种调用,会返回空指针异常
  @Test public void test14() {
      //        Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
      //        Foo mockTwo = mock(Foo.class, new YourOwnAnswer());
      //        //calling unstubbed method here:
      //        Stuff stuff = mock.getStuff();
      //        //using object returned by unstubbed call:
      //        stuff.doSomething();

  }

  //15
  //为进一步断言捕捉参数(Since 1.8.0)
  @Test public void test15() {
      //        ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
      //        verify(mock).doSomething(argument.capture());
      //        assertEquals("John", argument.getValue().getName());
  }

  public class Foo {
      public String someMethod(){
          return "real Method!";
      }
  }
  //16
  //真正的局部模拟 (Since 1.8.0)
  @Test public void test16() {
      //方法1.spy
      List list = spy(new LinkedList());

      //方法2.可以选择性的使用局部模拟
      Foo mock = mock(Foo.class);
      when(mock.someMethod()).thenCallRealMethod();
      System.out.println(mock.someMethod());
  }

  //17
  //模拟的重置(Since 1.8.0)
  @Test public void test17() {
      List mock = mock(List.class);
      when(mock.size()).thenReturn(10);
      System.out.println(mock.size());

      reset(mock);
      System.out.println(mock.size());
  }

  //18

  //19
  //行为驱动开发(behavior driven development - BDD)
  @Test public void shouldBuyBread19() {
      //        Seller seller = mock(Seller.class);
      //        Shop shop = new Shop(seller);
      //
      //        //given
      //        given(seller.askForBread()).willReturn(new Bread());
      //        //when
      //        Goods goods = shop.buyBread();
      //        //then
      //        assertThat(goods, containBread());
  }

  //20
  //序列化的模拟 (Since 1.8.1)
  @Test public void test20() {
      //1
      List serializableMock = mock(List.class, withSettings().serializable());

      //2
      List<Object> list = new ArrayList<Object>();
      List<Object> spy = mock(ArrayList.class, withSettings()
              .spiedInstance(list)
              .defaultAnswer(CALLS_REAL_METHODS)
              .serializable());
  }

  //21
  //注解: @Captor, @Spy, @InjectMocks (Since 1.8.3)

  //22
  //验证超时 (Since 1.8.5)
  @Test public void test22() {

      Foo mock = mock(Foo.class);
      //passes when someMethod() is called within given time span
      verify(mock, timeout(100)).someMethod();
      //above is an alias to:
      verify(mock, timeout(100).times(1)).someMethod();

      //passes when someMethod() is called *exactly* 2 times within given time span
      verify(mock, timeout(100).times(2)).someMethod();

      //passes when someMethod() is called *at lest* 2 times within given time span
      verify(mock, timeout(100).atLeast(2)).someMethod();

      //verifies someMethod() within given time span using given verification mode
      //useful only if you have your own custom verification modes.
      //      verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();
  }

  //23
  //@Spies, @InjectMocks 注释更优雅的(相对于1.8.3)注入方式 (Since 1.9)
  @Test public void test23() {
      //        //代替:
      //        @Spy BeerDrinker drinker = new BeerDrinker();
      //        //你可以写成:
      //        @Spy BeerDrinker drinker;
      //
      //        //同样适用于 @InjectMocks 注释:
      //        @InjectMocks LocalPub;
  }

  //24
  //用链式方法进行打桩 (Since 1.9)
  @Test public void test24() {
      //        Car boringStubbedCar = when(mock(Car.class).shiftGear()).thenThrow(EngineNotStarted.class).getMock();
  }

  //25
  //验证被忽视的桩 (Since 1.9)
  @Test public void test25() {
      //        verify(mock).foo();
      //        verify(mockTwo).bar();
      //
      //        //ignores all stubbed methods:
      //        verifyNoMoreInvocations(ignoreStubs(mock, mockTwo));
      //
      //        //creates InOrder that will ignore stubbed
      //        InOrder inOrder = inOrder(ignoreStubs(mock, mockTwo));
      //        inOrder.verify(mock).foo();
      //        inOrder.verify(mockTwo).bar();
      //        inOrder.verifyNoMoreInteractions();

  }
}

Maven2

| Comments

安装

1
 sudo apt-get install maven2

功能

Maven作为Apache的一个开源项目,旨在给项目管理提供更多的支持,主 页地址为Maven2 它最早的意图只是为了给apache组织的几个项目提供统一的开发、测试、打包和部署,能让开发者在多个项目中方便的切换

  • 项目标准化
  • 文档和报告
  • 类库管理
  • 发布管理

依赖库管理及目录

pom.xml格式以及使用

相关命令

使用

下面的图简单说明了maven2的使用

创建的目录结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
s2si
|-- pom.xml // 文档对象模型 Maven项目级配置文件  
`-- src
  |-- main
  |   `-- java
  |       `-- cn
  |           `-- bisoft
  |               `-- java
  |                   `-- app // 源代码目录  
  `-- test
      `-- java
          `-- cn
              `-- bisoft
                  `-- java
                      `-- app // 单元测试代码目录  

自己实验使用步骤

根据模板创建工程

可以使用

1
mvn archetype:generate

进行创建,但是太多模板,无法选择,需要利用过滤器缩小list。比如我只需要最基本的模板,输入下面的命令

1
mvn archetype:generate -Dfilter=quick

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> com.agilejava.docbkx:docbkx-quickstart-archetype (-)
2: remote -> com.alibaba.citrus.sample:archetype-webx-quickstart (-)
3: remote -> com.mysema.rdf:rdfbean-tapestry-quickstart (Archetype for creating a basic RDFBean Tapestry 5 application.)
4: remote -> com.mysema.rdfbean:rdfbean-tapestry-quickstart (-)
5: remote -> com.sun.jersey.archetypes:jersey-quickstart-ejb (An archetype which contains a simple Jersey based EJB project.)
6: remote -> com.sun.jersey.archetypes:jersey-quickstart-grizzly (An archetype which contains a quickstart Jersey project based on Grizzly container.)
7: remote -> com.sun.jersey.archetypes:jersey-quickstart-grizzly2 (An archetype which contains a quickstart Jersey project based on Grizzly2 container.)
8: remote -> com.sun.jersey.archetypes:jersey-quickstart-webapp (An archetype which contains a sample Jersey based Webapp project.)
9: remote -> de.akquinet.android.archetypes:android-quickstart (Creates a skeleton for an Android application)
10: remote -> de.akquinet.chameria:chameria-quickstart-archetype (-)
11: remote -> de.akquinet.javascript.archetypes:javascript-quickstart (-)
12: remote -> de.cologneintelligence:archetype-fitgoodies-quickstart (Archetype which generates an FitGoodies-enabled example project)
13: remote -> net.contextfw:web-quickstart (Context Web Application Framework - Quickstart)
14: remote -> net.devonlinux.solr:solr-quickstart-archetype (-)
15: remote -> net.devonlinux.solr:solr-quickstart-archetype-no-acceptance-tests (-)
16: remote -> org.apache.isis:quickstart-archetype (-)
17: remote -> org.apache.maven.archetypes:maven-archetype-quickstart (An archetype which contains a sample Maven project.)
18: remote -> org.apache.tapestry:quickstart (-)
19: remote -> org.apache.tuscany.sca:tuscany-quickstart (Create a simple Apache Tuscany SCA webapp project)
20: remote -> org.apache.tuscany.sca:tuscany-quickstart-bpel (Create an SCA Webapp project using BPEL)
21: remote -> org.apache.tuscany.sca:tuscany-quickstart-jsf (Create a Tuscany SCA and JSF project)
22: remote -> org.apache.tuscany.sca:tuscany-quickstart-jsonp (-)
23: remote -> org.apache.tuscany.sca:tuscany-quickstart-stripes (Create a simple Apache Tuscany SCA webapp project using the Stripes Web Framework)
24: remote -> org.apache.wicket:wicket-archetype-quickstart (-)
25: remote -> org.glassfish.jersey.archetypes:jersey-quickstart-grizzly2 (An archetype which contains a quick start Jersey project based on Grizzly container.)
26: remote -> org.glassfish.jersey.archetypes:jersey-quickstart-webapp (An archetype which contains a quick start Jersey-based web application project.)
27: remote -> org.hibernate:hibernate-search-quickstart (-)
28: remote -> org.hibernate:hibernate-validator-quickstart-archetype (Aggregator of the Hibernate Validator modules.)
29: remote -> org.jboss.errai.archetypes:bus-quickstart (-)
30: remote -> org.jboss.errai.archetypes:cdi-quickstart (-)
31: remote -> org.jboss.errai.archetypes:jaxrs-quickstart (-)
32: remote -> org.jboss.errai.archetypes:kitchensink-quickstart (A starter Errai + Java EE 6 webapp project for use on JBoss AS 7 / EAP 6, generated from the kitchensink-quickstart archetype)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 17:

根据包结构调整源码目录

添加依赖

因为项目依赖于Apache Mina以及log4j等,在pom.xml中添加如下字段

log4j依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
mina依赖
1
2
3
4
5
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.4</version>
</dependency>

5指定jdk版本

因为截至我使用的Maven 2.2.1 版本默认是利用jdk1.4进行编译,部分新特性无法用到,需要人工指定jdk版本,在pom.xml中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
<>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>

指定1.6版本进行编译

运行时依赖

利用

1
java -cp target/PSClient-1.0.jar com.cloudtv.PSClient.TestClient

编译打包正确,但是运行时出现错误,看提示应该是没有找到依赖的jar包.解决方式 有两种,一种是打包为war包,然后利用tomcat进行发布;另一种是将依赖包也打入 相应的路径,还是jar包,只不过需要早pox.xml中的plugins下面添加子字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>theMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin><plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>theMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>

Java设计模式

| Comments

Factory Method

  1. Product 定义了由factory method创建对象的统一接口
  2. ConcreteProduct是具体的类
  3. Creator为一般抽象类,声明若干factory method方法
  4. ConcreteCreator重载factory method创建某个ConcreteProduct

下面是JavaMail的结构

重用性说明

扩展性说明

如果有新的邮件协议为NewP,扩展Store为NewPStore, 扩展新类NewPFolder以及NewPMessage

带参数的模式

Parameterized Factory

对于Parameterized factory method模式,其factory method有一参数,用于指明需创建的对象的类型,这样一个类的factory method可以创建多种具体类型(ConcreteProduct)的对象,与Factory Method相同的是它所创建的对象都具有同样的接口Product

Factory Method 模式在 Javamail 中的应用

Observer模式

Apache Mina

| Comments

安装配置

简介

  • NIO framework library,
  • client server framework library, or
  • a networking socket library.

简单的时间函数例子

TimeServer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class MinaTimeServer
{
  private static final int PORT = 9123;

  public static void main( String[] args ) throws IOException
  {
      IoAcceptor acceptor = new NioSocketAcceptor();

      acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
      acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));

      acceptor.setHandler( new TimeServerHandler() );
      acceptor.getSessionConfig().setReadBufferSize( 2048 );
      acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
      acceptor.bind( new InetSocketAddress(PORT) );
  }
}

下面是Handler代码

Handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.Date;

import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

public class TimeServerHandler extends IoHandlerAdapter
{
  @Override
      public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
      {
          cause.printStackTrace();
      }

  @Override
      public void messageReceived( IoSession session, Object message ) throws Exception
      {
          String str = message.toString();
          if( str.trim().equalsIgnoreCase("quit") ) {
              session.close();
              return;
          }

          Date date = new Date();
          session.write( date.toString() );
          System.out.println("Message written...");
      }

  @Override
      public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
      {
          System.out.println( "IDLE " + session.getIdleCount( status ));
      }
}

在shell里运行

1
$telnet 127.0.0.1 9123

日志配置

在工程的src下建立log4j.properties文件,添加代码如下

1
2
3
4
5
6
7
8
9
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c{1} %x - %m%n

在主函数中添加

1
2
LoggingFilter loggingFilter = new LoggingFilter();
chain.addLast("logging", loggingFilter);

IoBuffer

替代NIO中的ByteBuffer的,原因如下

  • ByteBuffer没有提供fill, get/putString, get/putAsciiInt()等获取放入函数
  • ByteBuffer对于变长数据处理不好

这种解决方式并不佳,Bufer就是Buffer,只是临时存储数据的。并且这种包装不是 zero-copy的,也许用InputStream 替代byte buffer是一个更好的办法,相信这些会在Mina 3中改变。

初始化IoBuffer

1
2
3
4
5
// Allocates a new buffer with a specific size, defining its type (direct or heap)
public static IoBuffer allocate(int capacity, boolean direct)

// Allocates a new buffer with a specific size
public static IoBuffer allocate(int capacity)

创建自增的IoBuffer

在3.0版本中会被移除,使用InputStream或者固定大小buffer替代

1
2
3
4
5
6
7
IoBuffer buffer = IoBuffer.allocate(8);
buffer.setAutoExpand(true);

buffer.putString("12345678", encoder);

// Add more to this buffer
buffer.put((byte)10);

自减空间的buffer

1
2
3
4
5
6
7
8
9
10
11
IoBuffer buffer = IoBuffer.allocate(16);
buffer.setAutoShrink(true);
buffer.put((byte)1);
System.out.println("Initial Buffer capacity = "+buffer.capacity());
buffer.shrink();
System.out.println("Initial Buffer capacity after shrink = "+buffer.capacity());

buffer.capacity(32);
System.out.println("Buffer capacity after incrementing capacity to 32 = "+buffer.capacity());
buffer.shrink();
System.out.println("Buffer capacity after shrink= "+buffer.capacity());

IoHandler

Handler处理所有的I/O事件,处于过滤链底部,包含下列函数

  • sessionCreated
  • sessionOpened
  • sessionClosed
  • sessionIdle
  • exceptionCaught
  • messageReceived
  • messageSent

sessionCreated Event

链接创建触发该事件

sessionOpened Event

紧跟在sessionCreated后面触发该事件

sessionClosed Event

一旦session关闭,则触发该事件

sessionIdle Event

一旦session处于空闲状态触发该事件,udp没有该函数

exceptionCaught Event

异常触发该事件,如果是IOException则关闭socket

messageReceived Event

一旦接收到消息则触发该事件,大多数应用从这里开始,需要自己处理消息类型

messageSent Event

一旦消息响应发送回去触发该事件,发送通过IoSession.write()返回

参考