Newbie: Netty & Spring

Nicholas Hagen nicholas.hagen at znetdevelopment.com
Wed Aug 19 22:40:25 EDT 2009


As promised, here are some of my latest examples of how I have been  
using Spring using autowiring and annotations within Spring (version  
2.5.6).

Step 1:

/META-INF/applicationContext.xml
- this specifies the properties required to enable annotation  
processing and auto detection.  Change com.xyz in base-package to the  
base package (and subpackages) to be searched for annotations.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/ 
beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
                            http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<!-- auto discover annotated classes -->
	<context:component-scan base-package="com.xyz" />
	
	<!-- support annotated classes and properties -->
	<context:annotation-config/>

</beans>

Step 2:

Start application and spring application context

    public static void main(String[] args)
         throws Exception
     {
         // load and start spring
         ApplicationContext context = new ClassPathXmlApplicationContext
         (
             new String[] { "/META-INF/applicationContext.xml" }
         );

	// load server
	MyServer server = (MyServer) context.getBean("myServer",  
MyServer.class);
	server.start();
     }

Step 3:

Define server as a spring bean responsible for setting up Netty.

@Component
public class MyServer
{
     @Autowired
     private MyServerPipelineFactory _pipelineFactory;

     private Channel _server;

     public MyServer()
     {
         super();
     }

     public void start()
     {
         // configure factory
         ChannelFactory factory = new NioServerSocketChannelFactory
         (
             Executors.newCachedThreadPool(),
             Executors.newCachedThreadPool()
         );

         // configure pipeline factory and bootstrap
         ServerBootstrap bootstrap = new ServerBootstrap(factory);
         bootstrap.setPipelineFactory(this._pipelineFactory);
         // bootstrap.setOption("child.tcpNoDelay", true);
         // bootstrap.setOption("child.keepAlive", true);

         // bind and start to accept incoming connections
         this._server = bootstrap.bind(new InetSocketAddress(TCP_PORT));
     }

Step 4:

Define the custom pipeline factory for creating the relevant handlers.

@Component
public class MyServerPipelineFactory implements ChannelPipelineFactory
{
     @Autowired
     private MyRequestHandler _handler;

     public ChannelPipeline getPipeline() throws Exception
     {
         // create a default pipeline implementation
         ChannelPipeline pipeline = Channels.pipeline();

	// setup whatever encoders/decoders you need
         pipeline.addLast("decoder", new StringDecoder());
         pipeline.addLast("encoder", new StringEncoder());

	// add processing handler (auto-injected via spring)
         pipeline.addLast("handler", this._handler);

	// return pipeline
         return pipeline;
     }

}

Step 5:

Define the processing handler to handle business logic

@Component
@ChannelPipelineCoverage(ChannelPipelineCoverage.ALL)
public class MyRequestHandler extends SimpleChannelUpstreamHandler
{
     // inject other spring beans as you need
     @Autowired
     private OtherSpringBeans _otherSpringBean;

     @Override
     public void exceptionCaught(ChannelHandlerContext ctx,  
ExceptionEvent event)
         throws Exception
     {
         event.getCause().printStackTrace();
         event.getChannel().close();
     }

     @Override
     public void messageReceived(ChannelHandlerContext ctx,  
MessageEvent event)
         throws Exception
     {
         // handle event and its object (ie: string for string decoder)
         // use any autowired beans to perform logic against it
     }
}

That is the basic path I follow.  Now I can easily add and inject  
beans by simply declaring a class, marking it as a spring @Component,  
and then adding the @Autowire to the class.  I have been doing this  
for a few different projects now and it is extremely beneficial.  For  
example, it allows you to change implementations by creating a  
different @Component instance.

The problem with this approach though is that as the handler is  
injected into a singleton class, the handler is also a singleton.   
Thus, you cannot do a stateful handler that is request specific.   
There may be a way to do that within Spring, but I have not  
investigated as I have had no need yet.  Generally, my business logic  
is not stateful, just the decoders (ie: frame decoder) is stateful and  
those are manually created in the pipeline.

Other things you can do as well is inject a list of handlers into a  
class such as @Autowire List<Handler> _handlers.  In that case, Spring  
will find every @Component that implements Handler and inject as a  
list.  Then, just add each of those handlers to the pipeline.  Using  
this approach, you can add handlers automatically to a pipeline by  
merely creating a new class and marking it as a @Component.  That  
really simplifies and abstracts the pipeline.  The problem here is  
that there is no order defined for the handlers in the list and the  
order generally matters in the pipeline.  You could solve that by  
providing some annotation and processing that annotaiton while  
building the pipeline.  Alternatively, you could mark the handlers as  
Comparable and then use a sorted list letting the handlers compare  
against themselves (maybe using some order constant defined in each  
class).

Anyways, if you need further help or understanding, let me know.

Thanks,

=================================
Nicholas Hagen
Software Engineer
www.znetdevelopment.com
=================================
Coming Soon:  Push RSS
RSS Viewer (Push) for iPhone OS 3
www.znetdevelopment.com/znet/iphone.html
=================================

On Aug 19, 2009, at 3:18 PM, Nicholas Hagen wrote:

> I have examples I'll forward to the list later tonite.
>
> Nicholas Hagen
> Software Engineer
> www.znetdevelopment.com/blogs
> * sent from my iPhone *
>
> On Aug 19, 2009, at 1:51 PM, Simon James <sjames at btisystems.com>  
> wrote:
>
>>
>>
>> Are there any documented examples of how to use Spring to create and
>> bind a
>> pipeline for a simple standalone server, for example like the
>> TimeServer in
>> the user guide?
>>
>> I apologize if this is not the appropriate place for this question.
>> I have
>> searched the forums and other online resources, but failed to find
>> anything
>> specific.
>> -- 
>> View this message in context: http://n2.nabble.com/Newbie%3A-Netty---Spring-tp3474198p3474198.html
>> Sent from the Netty User Group mailing list archive at Nabble.com.
>> _______________________________________________
>> netty-users mailing list
>> netty-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/netty-users
> _______________________________________________
> netty-users mailing list
> netty-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/netty-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/netty-users/attachments/20090819/f3ffe004/attachment-0001.html 


More information about the netty-users mailing list