http协议是基于TCP的一种应用层协议,因为我们可以自己通过tcp的数据来进行编解码http协议。一般情况下,我们都是通过request对象和response对象进行与用户进行交互的。
netty是一款对用户非常友好的网络框架,更甚者提供了大量的基于tcp的用户层的协议封装,我们可以直接使用,因为在netty注册编解码器的时候,我们只需要加上netty自带的http的编解码器,就可以在接收和发送数据的时候采用request对象和response对象。
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
这样子,初步的我们的netty已经可以与客户端之间进行http协议的通讯,但是这种通讯是属于静态的内容的,没有办法与本文所说结合springmvc借助springmvc的controller来处理业务逻辑。还记得springmvc的入口吗?org.springframework.web.servlet.DispatcherServlet这个servlet就是springmvc的入口,其实思路就是我们只需要调用这个servlet的service方法,然后里面的处理就会直接给springmvc接管了,因此我们要初始化这个servlet。
private final DispatcherServlet dispatcherServlet;
public DispatcherServletChannelInitializer() throws ServletException {
MockServletContext servletContext = new MockServletContext();
MockServletConfig servletConfig = new MockServletConfig(servletContext);
servletConfig.addInitParameter("contextConfigLocation","classpath:/META-INF/spring/root-context.xml");
servletContext.addInitParameter("contextConfigLocation","classpath:/META-INF/spring/root-context.xml");
//AnnotationConfigWebApplicationContext wac = new AnnotationConfigWebApplicationContext();
XmlWebApplicationContext wac = new XmlWebApplicationContext();//采用xml的配置形式加载spring文件,初始化springmvc的context
//ClassPathXmlApplicationContext wac = new ClassPathXmlApplicationContext();
wac.setServletContext(servletContext);
wac.setServletConfig(servletConfig);
wac.setConfigLocation("classpath:/servlet-context.xml");
//wac.register(WebConfig.class);
wac.refresh();
this.dispatcherServlet = new DispatcherServlet(wac);
this.dispatcherServlet.init(servletConfig);
}
已经存在servlet,要调用servlet的service接口,让我们看看servlet的service方法定义。
protected void service(HttpServletRequest request, HttpServletResponse response)
这个service方法的参数是HttpServletRequest和HttpServletResponse,因为我们接下来的目标就是将netty的HttpRequest和HttpResponse对象与servlet的对象进行相互转换。我采用了springtest提供的用来模拟HttpServletRequest和HttpServletResponse的类,这两个类也是它们的子类。
org.springframework.mock.web.MockHttpServletRequest;org.springframework.mock.web.MockHttpServletResponse;
@Override
public void messageReceived(ChannelHandlerContext ctx, HttpRequest request) throws Exception {
if (!request.getDecoderResult().isSuccess()) {
sendError(ctx, BAD_REQUEST);
return;
}
MockHttpServletRequest servletRequest = createServletRequest(request);
MockHttpServletResponse servletResponse = new MockHttpServletResponse();
this.servlet.service(servletRequest, servletResponse);
HttpResponseStatus status = HttpResponseStatus.valueOf(servletResponse.getStatus());
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
for (String name : servletResponse.getHeaderNames()) {
for (Object value : servletResponse.getHeaderValues(name)) {
response.addHeader(name, value);
}
}
// Write the initial line and the header.
ctx.write(response);
InputStream contentStream = new ByteArrayInputStream(servletResponse.getContentAsByteArray());
// Write the content.
ChannelFuture writeFuture = ctx.write(new ChunkedStream(contentStream));
writeFuture.addListener(ChannelFutureListener.CLOSE);
}
最后直接在netty的回调方法中,进行处理和转换就OK了。遗憾的是,因为在代码里面并没有整合jsp和servlet容器,容易没办法处理正常的jsp页面,只能够将其作为http服务发布。
欢迎工作一到五年的Java工程师朋友们加入Java架构开发:855801563
群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代
网友评论