Netty之HTTP+XML编解码框架开发
一.HTTP+XML请求消息编码类
对于上层业务,构造订购请求消息后,以HTTP+XML协议将消息发送给服务端,如果要实现对业务零侵入或者尽可能少的侵入看,协议层和应用层应该解耦。
考虑到HTTP+XML协议栈需要一定的定制扩展能力,例如通过HTTP消息头携带业务自定义字段,应该允许业务利用Netty的HTTP协议栈接口自行构造私有的HTTP消息头。
HTTP+XML的协议编码仍然采用ChannelPipeline中增加对应的编码handler类实现。
1.1 HttpXmlRequestEncode实现
packagejibx;
import java.net.InetAddress;
import java.util.List;
importio.netty.channel.ChannelHandlerContext;
importio.netty.handler.codec.http.DefaultFullHttpRequest;
importio.netty.handler.codec.http.FullHttpRequest;
importio.netty.handler.codec.http.HttpHeaders;
/*
*HTTP+XML HTTP请求消息编码类
*
*/
public class HttpXmlRequestEncoder
extends AbstarctHttpXmlEncoder<HttpXmlRequest>{
@Override
protected void encode(ChannelHandlerContext ctx,HttpXmlRequestmsg,List<Object> out)
throws Exception{
// 调用父类的encode0,将业务需要发送的POJO对象Order实例通过jibx序列化为XML字符串
// 随后将它封装成netty的bytebuf
ByteBufbody=encode0(ctx,msg.getBody());
FullHttpRequestrequest=msg.getRequest();
// 对消息头进行判断,如果业务侧自定义和定制了消息头,则使用业务侧设置的HTTP消息头
// 如果业务侧没有设置,则构造新的HTTP消息头
if(request==null){
// 构造和设置默认的HTTP消息头,由于通常情况下HTTP通信双方更关注消息体本身,
// 所以这里采用了硬编码方式,如果要产品化,可以做成XML配置文件,允许业务自定义配置,
// 以提升定制的灵活性
request=newDefaultFullHttpRequest(HttpVersion.HTTP_1_1,HttpMethod.GET,"/do",body);
HttpHeadersheaders=request.headers();
headers.set(HttpHeaders.Names.HOST,InetAddress.getLocalHost().getHostAddress());
headers.set(HttpHeaders.Names.CONNECTION,HttpHeaders.Value.CLOSE);
headers.set(HttpHeaders.Names.ACCEPT_ENCODING,HttpHeaders.Value.GZIP.toString()+','+
HttpHeaders.Value.DEFLATE.toString());
headers.set(HttpHeaders.Names.ACCEPT_CHARSET,"ISO-8859,utf-8,q=0.7,*;q=0.7");
headers.set(HttpHeaders.Names.USER_AGENT,"Nettyxml Http Client side");
headers.set(HttpHeaders.Names.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8");
}
// 由于请求消息消息体不为空,也没有chunk方式,所以在HTTP消息头中设置消息体的长度conent-length
// 完成消息体的XML序列化后将重新构造的HTTP请求消息加入到out中
// 由后续netty的http请求编码器继续对HTTP请求消息进行编码
HttpHeaders.setContentLength(request,body.eradableBytes());
out.add(request);
}
}
1.2 AbstrctHttpXmlEncoder实现
package jibx;
import java.io.StringWriter;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
importio.netty.channel.ChannelHandlerContext;
importio.netty.handler.codec.MessageToMessageEncoder;
/*
*HTTP+XML HTTP请求消息编码基类
*/
public classAbstractHttpXmlEncoder<T>
extends MessageToMessageEncoder<T>{
IBindingFactoryfactory=null;
StringWriterwriter=null;
finalstatic String CHARSET_NAME="UTF-8";
finalstatic Charset UTF-8=
Charset.forName(CHARSET_NAME);
//将业务的Order实例序列化为XML字符串
protectedByteBuf encode0(ChannelHandlerContext ctx,Object body) throws Exception{
factory=BindingDirectory.getFactory(body.getClass());
writer=newStringWriter();
IMarshallingContextmctx=factory.createMarshallingContext();
mctx.setIndent(2);
mctx.marshalDocument(body,CHARSET_NAME,null,writer);
StringxmlStr=writer.toString();
writer.close();
writer=null;
//将XML字符串包装成netty的ByteBuf并返回,实现了HTTP请求消息的XML编码
ByteBufencodeBuf=Unpooled.copiedBuffer(xmlStr,UTF-8);
returnencodeBuf;
}
@Override
publicvoid exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throwsException{
//释放资源
if(writer!=null){
writer.close();
writer=null;
}
}
}
1.3 HttpXmlRequest实现
package jibx;
/*
*HTTP+XML请求消息 用于实现和协议栈之间的解耦
*/
importio.netty.handler.codec.http.FullHttpRequest;
public class HttpXmlRequest {
privateFullHttpRequest request;
privateObject body;
publicHttpXmlRequest(FullHttpRequest request,Object body){
this.request=request;
this.body=body;
}
publicfinal FullHttpRequest getRequest(){
returnrequest;
}
publicfinal void setRequest(FullHttpRequest request){
this.request=request;
}
publicfinal Object getBody(){
returnbody;
}
publicfinal void setBody(Object body){