CometD 2 Java Server Services Spring Integration
CometD 2 Services Integration with Spring
Integration of CometD services with Spring is particularly interesting, since most of the times your Bayeux services will require other beans to perform their service.
Not all Bayeux services are as simple as the EchoService, and having Spring's dependency injection (as well as other facilities) integrated greatly simplifies development.
The following instructions are valid from the 2.1.0 release onwards.
XML Based Spring Configuration
The BayeuxServer object is directly configured and initialized in the Spring configuration file, and injects it in the servlet context, where it is picked up by the CometD servlet, which performs no further configuration or initialization.
The web.xml file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.server.CometdServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Spring's applicationContext.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="otherService" class="com.acme..." />
<bean id="bayeux" class="org.cometd.server.BayeuxServerImpl" init-method="start" destroy-method="stop">
<property name="options">
<map>
<entry key="logLevel" value="3" />
<entry key="timeout" value="15000" />
</map>
</property>
</bean>
<bean id="echoService" class="com.acme.cometd.EchoService">
<constructor-arg><ref local="bayeux" /></constructor-arg>
<constructor-arg><ref local="otherService" /></constructor-arg>
</bean>
<bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="org.cometd.bayeux">
<ref local="bayeux" />
</entry>
</map>
</property>
</bean>
</beans>
The BayeuxServer object is now created by Spring, configured via the options property, initialized via the start() method, and exported to the servlet context via Spring's ServletContextAttributeExporter.
Differently from CometD 1's Spring integration, in CometD 2 the BayeuxServer object created in this way is fully functional, and therefore there is no need to mark dependent services as lazy, and no need for glue code.
Annotation Based Spring Configuration
Spring 3.x supports annotation based configuration and annotated services integrate nicely with Spring 3.x.
Spring 3.x is required over Spring 2.5.x because it supports injection via JSR 330.
Prerequisite to make Spring 3.x work with CometD annotated services is to have JSR 330's javax.inject classes in the classpath along with JSR 250's javax.annotation classes (these are included in JDK 6 and therefore only required if you use JDK 5).
Do not forget that Spring 3.x requires CGLIB classes in the classpath as well.
The web.xml file is exactly equal to the one given as example in the XML based configuration above.
Spring's applicationContext.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.acme..." />
</beans>
Spring will scan the classpath for classes that qualify as Spring beans in the given base package.
The CometD annotated service needs some additional annotation to make it qualify as a Spring bean:
@javax.inject.Named // Tells Spring that this is a bean @javax.inject.Singleton // Tells Spring that this is a singleton @Service("echoService") public class EchoService { @Inject private BayeuxServer bayeux; @Session private ServerSession serverSession; @PostConstruct public void init() { System.out.println("Echo Service Initialized"); } @Listener("/echo") public void echo(ServerSession remote, ServerMessage.Mutable message) { String channel = message.getChannel(); Object data = message.getData(); remote.deliver(serverSession, channel, data, null); } }
The missing piece is that we need to tell Spring to perform the processing of the CometD annotations, and we do so using a Spring component:
@Component
public class Configurer implements DestructionAwareBeanPostProcessor, ServletContextAware
{
private BayeuxServer bayeuxServer;
private ServerAnnotationProcessor processor;
@Inject
private void setBayeuxServer(BayeuxServer bayeuxServer)
{
this.bayeuxServer = bayeuxServer;
}
@PostConstruct
private void init()
{
this.processor = new ServerAnnotationProcessor(bayeuxServer);
}
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException
{
processor.processDependencies(bean);
processor.processConfigurations(bean);
processor.processCallbacks(bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException
{
return bean;
}
public void postProcessBeforeDestruction(Object bean, String name) throws BeansException
{
processor.deprocessCallbacks(bean);
}
@Bean(initMethod = "start", destroyMethod = "stop")
public BayeuxServer bayeuxServer()
{
BayeuxServerImpl bean = new BayeuxServerImpl();
bean.setOption(BayeuxServerImpl.LOG_LEVEL, "3");
return bean;
}
public void setServletContext(ServletContext servletContext)
{
servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer);
}
}
This Spring component is the factory for the BayeuxServer object via the bayeuxServer() method (annotated with Spring's @Bean).
It requires itself the BayeuxServer object in order to create CometD's ServerAnnotationProcessor, and therefore it @Injects it into a setter method.
The lifecycle callback init() takes care of creating CometD's ServerAnnotationProcessor, which is then used during Spring's bean post processing phases.
Finally, the BayeuxServer object is exported into the servlet context to be used by the CometD servlet.
- Printer-friendly version
- Login to post comments