Posts Tagged ‘Hessian’

选择或设计实现远程RPC调用所需要考虑的n个方面

星期三, 8月 27th, 2008

选择或设计实现远程RPC调用所需要考虑的n个方面

(前段时间记录的零散片段,却一直没时间仔细整理,仅记录在此,以做备忘。)
可参考协议(组件)为:
http,smtp,pop,ftp,dns,burlap,json,xml-rpc,xmpp,smpp,rmi,soap,hessian,thrift , protocol buffers等等
需要考虑以下方面:

必备条件:
a.多语言支持
b.强大的序列化和反序列化(xml,text,pdu,text+stream)
c.多种传输模式

1.服务端所支持的编程语言。
java,C,C++,C#,PHP等等

2.客户端支持的语言。
java,C,C++,JavaScript等

3.字节流转码。
支持GBK,UTF-8等。

4.支持的基础数据类型。
char,int,long,double,floadt,boolean,List,Map,Object(Struct)

5.同名重载方法区别

6.支持数据包的转发代理 (前端负载均衡)

7.自定义超时连接

8.数据包转换 (对象的序列化和反序列化)

9.数据类型扩展

10.类与接口实现的约束

11.是否支持负载限制 (比如超过100并发时,直接返回系统忙)

12.failover处理

13.事务控制

14.异步调用

15.数据包版本自动识别

16.TCP/UDP支持
(UDP 有1472字节限制。)

17.代码生成器(主要针对数据包的序列化)

18.与现有框架的整合难度(组件化程度)

19.大文件传输

21.数据包序列化效率

客户端连接池
应用范围

22.网络带宽约束(数据包是否支持压缩)

23.服务接口监控统计

数据包加密

SSL支持

是否需要握手消息(是需多次交互还是简单的请求应答模式)

调试抓包的方便性

是否支持双向调用(xmpp支持)

部署难易程度

参数配置难度

是否支持请求队列

请求应答的对应关系

协议可读性

支持客户端并发限制(比如同一ip每秒只能够调用10次)

断点续传和重发数据

URL设置

access.log配置与合并,自定义 logger(用于控制是否打印敏感信息)

过滤器拦截模式

接口代码可读性

常用端口选择

重启服务时的热切换

黏性会话支持(基于IP,或者基于sessionid)

安全端口

是否可以多端口

配置文件

是否能够方便获取真实客户端ip和端口
MDC支持
是否支持线程局部变量(类似webservice获取session,ICE的Current)

防雪崩(提供初始化预热加载)

Tags: google protobuf, Hessian, RPC, thrift

Related posts

HessianServlet和HessianProxyFactory的配置参数

星期日, 7月 27th, 2008

HessianServlet和HessianProxyFactory的配置参数

home-class,service-class,表示Service的实现类的类名

home-api,api-class,是Service的接口类名

object-class,不太了解
object-api,不太了解,

debug,调试开关,默认为false,需要设置为true的时候,值必须是”true”,区分大小写(不建议设置为true)

send-collection-type,设置SerializerFactory是否在序列化的数据里传递集合类的类型名,默认为true,需要设置为false的时候,
值必须是”false”,区分大小写(不建议设置为false)

其实 SerializerFactory还有个 _isAllowNonSerializable属性,控制是否接受对没有实现 java.io.Serializable接口的对象,
通过setAllowNonSerializable来控制,
默认是不接受,为false,而HessianServlet却没提供这个参数的控制开关,因此如果要支持传输没有实现java.io.Serializable接口的对象,
则需要继承HessianServlet来加上相应控制,重载getSerializerFactory方法来设置参数或增加扩展的SerializerFactory,
而无法通过直接配置HessianServlet的初始化参数来实现。

先前提到的 hessian  3.1.5里hession2.0 有bug ,在hessian 3.1.6里依然存在,在hessian 3.2.0中将被修正.

参考: http://maillist.caucho.com/pipermail/hessian-interest/2008-July/000405.html

ServiceContext存放了线程局部变量request,
ServiceContext.getContextRequest()

HessianProxyFactory 设置的 _isOverloadEnabled 可支持同名重载方法。
不过不建议在接口中使用同名方法和变长参数。
_user和_password是设置 http basic认证的用户名和密码。
_isDebug,调试开关
_isHessian2Reply,_isHessian2Request,是否使用hessian 2.0协议发送请求。
_isChunkedPost,设置Chunked编码方式发送请求。

Tags: Hessian, RPC

Related posts

slf4j 1.5.2 的MessageFormatter有个bug,对数组形式的消息没能正确格式化

星期日, 7月 20th, 2008

我下载的是最新的slf4j 1.5.2和logback 0.9.9,下载地址分别为:

http://www.slf4j.org/dist/slf4j-1.5.2.zip
来源:http://www.slf4j.org/download.html
http://logback.qos.ch/dist/logback-0.9.9.zip
来源:http://logback.qos.ch/download.html
用到的lib为:
logback-access-0.9.9-sources.jar
logback-access-0.9.9.jar
logback-classic-0.9.9-sources.jar
logback-classic-0.9.9.jar
logback-core-0.9.9-sources.jar
logback-core-0.9.9.jar
slf4j-api-1.5.2.jar
slf4j-api-1.5.2-sources.jar

写了个例子测试的时候发现:
slf4j在格式化日志信息内容时,没有对数组类型的对象进行判断。
以多个参数方式拼接日志信息之后,输出的内容成了下面这样的。
,byte:[B@b2002f,
,char:[C@2a4983,
,int:[I@406199,
,long:[J@c7b00c,
,double:[D@1f6f296,
,float:[F@1b09468,
,Object:[Ljava.lang.Object;@b2a2d8,
这不是我所期望的日志。

测试的logback.xml的配置为:
[code]
<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
<appender name=”CONSOLE” class=”ch.qos.logback.core.ConsoleAppender”>
<layout class=”ch.qos.logback.classic.PatternLayout”>
<pattern>%d %p %t %m %n</pattern>
</layout>
</appender>
<logger name=”com.lizongbo”>
<level value=”DEBUG”/>
<appender-ref ref=”CONSOLE”/>
</logger>
</configuration>

[/code]
测试代码为:
[code]

package com.lizongbo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogTest {

public static void main(String[] args) throws InterruptedException {
Logger log = LoggerFactory.getLogger(LogTest.class);
log.debug(”a:{},v:{},c:{},”, new Object[] {”A”, “C”,
new java.util.ArrayList() {
{
add(”lizongbo”);
}
}
});
log.debug(”a:{},v:{},c:{},”, new Object[] {”A”, “C”, null});
log.debug(”a:{},v:{},c:{},”, new Object[] {”A”, “C”, new java.util.Date()});
log.debug(”a:{},v:{},byte:{},”, new Object[] {”A”, “C”, new byte[] {1,2, 3} });
log.debug(”a:{},v:{},char:{},”, new Object[] {”A”, “C”, new char[] {41,42, 43} });
log.debug(”a:{},v:{},int:{},”, new Object[] {”A”, “C”, new int[] {618119, 400, 500} });
log.debug(”a:{},v:{},long:{},”, new Object[] {”A”, “C”, new long[] {1, 2, 3} });
log.debug(”a:{},v:{},double:{},”, new Object[] {”A”, “C”, new double[] {1, 2, 3} });
log.debug(”a:{},v:{},float:{},”, new Object[] {”A”, “C”, new float[] {1, 2, 3} });
log.debug(”a:{},v:{},float:{},”, new Object[] {”A”, “C”,new Object[] {1, “618119.com”, “lizongbo”} });
}
}
[/code]
修正这个bug之后的MessageFormatter.java的完整代码为:

[code]
/*
* Copyright (c) 2004-2007 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* “Software”), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package org.slf4j.helpers;

/**
* Formats messages according to very simple substitution rules. Substitutions
* can be made 1, 2 or more arguments.
*

* For example,
*

MessageFormatter.format("Hi {}.", "there");

* will return the string “Hi there.”.
*

* The {} pair is called the formatting anchor. It serves to
* designate the location where arguments need to be substituted within the
* message pattern.
*

* In the rare case where you need to place the ‘{’ or ‘}’ in the message
* pattern itself but do not want them to be interpreted as a formatting
* anchors, you can espace the ‘{’ character with ‘\’, that is the backslash
* character. Only the ‘{’ character should be escaped. There is no need to
* escape the ‘}’ character. For example,
*

MessageFormatter.format("Set \\{1,2,3} is not equal to {}.", "1,2");

* will return the string “Set {1,2,3} is not equal to 1,2.”.
*
*

* The escaping behaviour just described can be overridden by
* escaping the escape character ‘\’. Calling
*

MessageFormatter.format("File name is C:\\\\{}.", "file.zip");

* will return the string “File name is C:\file.zip”.
*
*

* See {@link #format(String, Object)}, {@link #format(String, Object, Object)}
* and {@link #arrayFormat(String, Object[])} methods for more details.
*
* @author Ceki Gülcü
*/
public class MessageFormatter {
static final char DELIM_START = ‘{’;
static final char DELIM_STOP = ‘}’;
private static final char ESCAPE_CHAR = ‘\\’;

/**
* Performs single argument substitution for the ‘messagePattern’ passed as
* parameter.
*

* For example,
*
*

     * MessageFormatter.format("Hi {}.", "there");
     *

*
* will return the string “Hi there.”.
*

*
* @param messagePattern
* The message pattern which will be parsed and formatted
* @param argument
* The argument to be substituted in place of the formatting anchor
* @return The formatted message
*/
public static String format(String messagePattern, Object arg) {
return arrayFormat(messagePattern, new Object[] {arg});
}

/**
*
* Performs a two argument substitution for the ‘messagePattern’ passed as
* parameter.
*

* For example,
*
*

     * MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");
     *

*
* will return the string “Hi Alice. My name is Bob.”.
*
* @param messagePattern
* The message pattern which will be parsed and formatted
* @param arg1
* The argument to be substituted in place of the first formatting
* anchor
* @param arg2
* The argument to be substituted in place of the second formatting
* anchor
* @return The formatted message
*/
public static String format(String messagePattern, Object arg1, Object arg2) {
return arrayFormat(messagePattern, new Object[] {arg1, arg2});
}

/**
* Same principle as the {@link #format(String, Object)} and
* {@link #format(String, Object, Object)} methods except that any number of
* arguments can be passed in an array.
*
* @param messagePattern
* The message pattern which will be parsed and formatted
* @param argArray
* An array of arguments to be substituted in place of formatting
* anchors
* @return The formatted message
*/
public static String arrayFormat(String messagePattern, Object[] argArray) {
if (messagePattern == null) {
return null;
}
int i = 0;
int len = messagePattern.length();
int j = messagePattern.indexOf(DELIM_START);

if (argArray == null) {
return messagePattern;
}

StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50);

for (int L = 0; L < argArray.length; L++) {

j = messagePattern.indexOf(DELIM_START, i);

if (j == -1 || (j + 1 == len)) {
// no more variables
if (i == 0) { // this is a simple string
return messagePattern;
} else { // add the tail string which contains no variables and return
// the result.
sbuf.append(messagePattern.substring(i,
messagePattern.length()));
return sbuf.toString();
}
} else {
char delimStop = messagePattern.charAt(j + 1);

if (isEscapedDelimeter(messagePattern, j)) {
if (!isDoubleEscaped(messagePattern, j)) {
L–; // DELIM_START was escaped, thus should not be incremented
sbuf.append(messagePattern.substring(i, j - 1));
sbuf.append(DELIM_START);
i = j + 1;
} else {
// The escape character preceding the delemiter start is
// itself escaped: “abc x:\\{}”
// we have to consume one backward slash
sbuf.append(messagePattern.substring(i, j - 1));
appendParam(sbuf, argArray[L]);
i = j + 2;
}
} else if ((delimStop != DELIM_STOP)) {
// invalid DELIM_START/DELIM_STOP pair
sbuf.append(messagePattern.substring(i,
messagePattern.length()));
return sbuf.toString();
} else {
// normal case
sbuf.append(messagePattern.substring(i, j));
appendParam(sbuf, argArray[L]);
i = j + 2;
}
}
}
// append the characters following the last {} pair.
sbuf.append(messagePattern.substring(i, messagePattern.length()));
return sbuf.toString();
}

/**
* append value ,check arrat type ,added by lizongbo ,增加了对数据类型的判断
* @param sb StringBuffer
* @param argArray Object
*/
static void appendParam(StringBuffer sb, Object argArray) {
if (argArray != null && argArray.getClass().isArray()) {
sb.append(’[');
if (argArray instanceof Object[]) {
Object[] value = (Object[]) argArray;
if (value.length > 0) {
for (int k = 0; k < value.length - 1; k++) {
sb.append(value[k]).append(’,');
}
sb.append(value[value.length - 1]);
}
} else if (argArray instanceof byte[]) {
byte[] value = (byte[]) argArray;
if (value.length > 0) {
for (int k = 0; k < value.length - 1; k++) {
sb.append(value[k]).append(’,');
}
sb.append(value[value.length - 1]);
}
} else if (argArray instanceof char[]) {
char[] value = (char[]) argArray;
sb.append(value);
} else if (argArray instanceof int[]) {
int[] value = (int[]) argArray;
if (value.length > 0) {
for (int k = 0; k < value.length - 1; k++) {
sb.append(value[k]).append(’,');
}
sb.append(value[value.length - 1]);
}
} else if (argArray instanceof long[]) {
long[] value = (long[]) argArray;
if (value.length > 0) {
for (int k = 0; k < value.length - 1; k++) {
sb.append(value[k]).append(’,');
}
sb.append(value[value.length - 1]);
}
} else if (argArray instanceof double[]) {
double[] value = (double[]) argArray;
if (value.length > 0) {
for (int k = 0; k < value.length - 1; k++) {
sb.append(value[k]).append(’,');
}
sb.append(value[value.length - 1]);
}
} else if (argArray instanceof float[]) {
float[] value = (float[]) argArray;
if (value.length > 0) {
for (int k = 0; k < value.length - 1; k++) {
sb.append(value[k]).append(’,');
}
sb.append(value[value.length - 1]);
}
}
sb.append(’]');
} else {
sb.append(argArray);
}

}

static boolean isEscapedDelimeter(String messagePattern,
int delimeterStartIndex) {

if (delimeterStartIndex == 0) {
return false;
}
char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
if (potentialEscape == ESCAPE_CHAR) {
return true;
} else {
return false;
}
}

static boolean isDoubleEscaped(String messagePattern,
int delimeterStartIndex) {
if (delimeterStartIndex >= 2
&& messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {
return true;
} else {
return false;
}
}
}

[/code]

修正bug之后运行结果为:

2008-07-20 02:03:19,093 DEBUG main a:A,v:C,c:[lizongbo],
2008-07-20 02:03:19,093 DEBUG main a:A,v:C,c:null,
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,c:Sun Jul 20 02:03:19 CST 2008,
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,byte:[1,2,3],
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,char:)*+,
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,int:[618119,400,500],
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,long:[1,2,3],
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,double:[1.0,2.0,3.0],
2008-07-20 02:03:19,109 DEBUG main a:A,v:C,float:[1.0,2.0,3.0],
2008-07-20 02:03:19,125 DEBUG main a:A,v:C,float:[1,618119.com,lizongbo],

顺便说一句,我曾经提到的hessianbug,终于在hessian 3.2.0里被修复了,

详情可见: http://bugs.caucho.com/view.php?id=2594

Tags: bug, Hessian, log, logback, slf4j

Related posts