Category Archives: Spring

SpringMVC with Netty

I’m using Spring/Hibernate to provide the Hypersocket REST API on a Netty based HTTP server. Why? well Hypersocket’s main function is a tunnelling server so the first priority is a high performance socket framework. The user interface implementation had to come second to this requirement; I certainly did not want to burden the server with an overweight server-side UI framework so I was looking for something that was lightweight. I also wanted support for Spring/Hibernate since it makes creating my domain model a breeze. So a Javascript based UI accessing REST services provided by SpringMVC controllers sounded ideal.

The problem I faced is that SpringMVC is run in a servlet container and there is no servlet implementation for Netty because the servlet API relies on the standard IO model of using InputStream/OutputStream. I decided to try and implement a lightweight servlet container for Netty so that I could plugin the Spring servlet. Here is a run down of how I managed to get this working.

I created implementations of the following servlet container interfaces. I’ll be posting a fully working example soon so I won’t go into the actual implementations here.

ServletConfig
ServletContext
HttpServletRequest
HttpServletResponse
HttpSession

Now I could start configuring my Spring environment so my domain objects are created in the usual way with a Spring ApplicationContext. Loading any application context files I’ve placed in the classpath:

ApplicationContext applicationContext = 
          new ClassPathXmlApplicationContext(
                 "classpath*:/META-INF/applicationContext.xml");

I had to code the configuration of the SpringMVC context because I don’t have a complete servlet container to configure from a web.xml file. I’ve literally just implemented the basic servlet API that will get the servlet working. So I created a AnnotationConfigWebApplicationContext (as I’m exclusively using annotations) and set my main ApplicationContext as parent:

AnnotationConfigWebApplicationContext webappContext
         = new AnnotationConfigWebApplicationContext();

// Use my main ApplicationContext as parent so it can discover my domain entities.
webappContext.setParent(applicationContext);

Next I register a DelegatingWebMvcConfiguration because I want to add a custom intercept handler for an annotation I will be creating. This will look for @Components that extend the WebMvcConfigurer interface. Even if you don’t want to add your own interceptors you should add this although you can use WebMvcConfigurationSupport instead.

webappContext.register(DelegatingWebMvcConfiguration.class);

Now setup the packages to scan for @Controller annotations:

webappContext.scan("com.hypersocket.example.web.**");

We can now setup our ServletConfig on the AnnotationConfigWebApplicationContext:

servletConfig = new HypersocketServletConfig("default", "/hypersocket");

// Set the servlet config on our AnnotationConfigWebApplicationContext
webappContext.setServletConfig(servletConfig);

Finally we can create the Spring DispatcherServlet:

dispatcherServlet = new DispatcherServlet(webappContext);

dispatcherServlet.init(servletConfig);

And there we have it, a configured DispatcherServlet that is ready to accept requests. The only thing left for us to do is to translate HTTP requests/responses from Netty into HttpServletRequest/HttpServletResponse. Here is my ChannelPipeline which uses Netty’s built-in HTTP encoder/decoder:

public ChannelPipeline getPipeline() throws Exception {
        // Create a default pipeline implementation.
        ChannelPipeline pipeline = pipeline();
        pipeline.addLast("decoder", new HttpRequestDecoder());
        pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
        pipeline.addLast("encoder", new HttpResponseEncoder());
        pipeline.addLast("handler", new HttpRequestDispatcherHandler(server));
        return pipeline;
}

This means when my HttpRequestDispatcherHandler receives a HTTP request all it has do is to translate this into a HttpServletRequest and pass this into the DispatcherServlet along with a HttpServletResponse. Upon return I then translate this back into Netty’s HttpResponse and the request is complete.

There are a number of improvements I could make, one would be to have Netty decode directly into a HttpServletRequest but that would tie the server to the servlet API and might not be appropriate for the tunneling services I’m adding but it may be appropriate for you. Another is the HttpSession support, presently its just a simple factory and some work is needed to ensure sessions are cleaned up after expiry.

I’ve only tested SpringMVC with @Controller classes that are sending/receiving entity objects with the @RequestBody, @ResponseBody annotations. I’ve not tried to use any other feature of SpringMVC so would welcome feedback if others are able to go further.