netty整合springmvc

    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服務發佈。


項目的完整代碼已經在https://github.com/linsongze/nettyholdspringmvc/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章