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);
}
作者:架构师springboot
链接:https://www.jianshu.com/p/ddd990254ece