Jencks is logically equivalent to the ActiveMQ JCA Container and migrating to it is pretty simple. The benefits of Jencks are that it supports full XA recovery and works well with Geronimo's TransactionManager and WorkManager.
So it is Spring and POJO enhancements to the Geronimo JCA container to implement Message Driven POJOs.
The JCA (Java Connector Architecture) provides the most efficient way of thread pooling, resource pooling, transaction handling and consumption on JMS and other Resource Adapters. So, if you are consuming JMS messages, the JCA container provides the most efficient way of pooling the JMS sessions and connections, pooling threads and processing messages in parallel as well as transaction and exception handling.
You can download the latest release of Jencks container from http://docs.codehaus.org/display/JCA/Download
So here are the steps to proceed:
1. Create a spring configuration file (service.xml) and insert the following lines:
<bean id="jencks" class="org.jencks.JCAContainer">
<property name="transactionManager" ref="transactionManager"/>
<property name="threadPoolSize" value="25"/>
<property name="resourceAdapter">
<bean id="activeMQResourceAdapter" class="org.apache.activemq.ra.ActiveMQResourceAdapter">
<property name="serverUrl" value="tcp://localhost:51616"/>
</bean>
</property>
</bean>
The above lines configure the JCA container. You can configure the thread pool size, transaction manager here.
You can also associate whichever JCA Resource Adapter you wish, such as to use another JMS provider. Since I am going to use ActiveMQ, have used ActiveMQResourceAdapter.
Insert below lines in service.xml to register Transaction Manager:
<bean id="transactionManager" class="org.jencks.factory.TransactionManagerFactoryBean"/>
Now you have to define ActiveMQ broker using
<bean id="broker" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="file:///c:/activemq/conf/mybroker.xml" />
</bean>
2. Now register your MDP with this container. Insert the following in service.xml
<bean id="connA" class="org.jencks.JCAConnector">
<property name="jcaContainer" ref="jencks" />
<property name="activationSpec">
<bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
<property name="destination" value="MyQueue"/>
<property name="destinationType" value="javax.jms.Queue"/>
</bean>
</property>
<property name="ref" value="HelloBean"/>
</bean>
<bean id="HelloBean" class="test.mdp.HelloBean" singleton="true"/>
For Topics, just change the ActiveMQActivationSpec.
<bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
<property name="destination" value="MyTopiv"/>
<property name="destinationType" value="javax.jms.Topic"/>
</bean>
The above lines of configuration create stateful, pooled MessageListener.
The activation specification is dependent on the JCA Resource Adapter being used. If you are using ActiveMQ as your resource adapter then you can configure are all the various properties here, giving you full control over every aspect of the JMS subscription, pooling and delivery mode. For ActiveMQ adapter you can find the properties available at http://activemq.apache.org/activation-spec-properties.html
The POJO which implements the JMS MessageListener interface is referenced via the ref property in the connector. The HelloBean in this example can be any POJO created by Spring. If you wish you can use a spring singleton, or can add your own Spring interceptors around it - though note that Jencks already takes care of security and transaction handling for you automatically.
Note: If you are using XA transactions on inbound messages and want to support recovery then you must specify an id or name in the Spring XML configuration for the inbound connector as shown above.
3. Required JARs are:
4. Some key points about Jencks Container:
a. concurrency of message processing: One of the main points of using JCA is to allow you to process inbound messages concurrently in a thread pool using a pool of JMS connections and sessions. There are 2 main configuration points you can use in Jencks
--the thread pool size defines the maximum number of concurrent messages that can be processed in Jencks across any subscription in that JCAContainer.
--for some ActivationSpec implementations you can further configure the subscription to define the concurrency model. For example in ActiveMQ you can specify the maxSessions and maxMessagesPerSessions properties to configure how many concurrent messages can be processed for that subscription.
Using both approaches you can define how many threads are used for all the subscriptions and also how many of those threads can be used up by each subscription. This means you can segment your subscriptions to ensure one subscription doesn't overload other subscriptions.
You can also create multiple JCAContainer instances to allow you to have completely separate thread pools for different kinds of subscriptions if you wish.
b: To use XA for an inbound connection in the JCA container you'll need to specify a transaction manager to the inbound connector. Here's an example
<bean id="inboundConnectorA" class="org.jencks.JCAConnector">
<property name="jcaContainer" ref="jencks"/>
<property name="activationSpec">
<bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
<property name="destination" value="test.spring.inboundConnectorA"/>
<property name="destinationType" value="javax.jms.Topic"/>
</bean>
</property>
<!-- use XA transactions -->
<property name="transactionManager" ref="transactionManager"/>
<property name="ref" value="HelloBean"/>
</bean>
You also need to provide a transaction manager implementation to use.
<bean id="transactionManager" class="org.jencks.factory.TransactionManagerFactoryBean"/>
Outbound Messaging:
Jencks not only supports Inbound JMS messaging but also outbound messaging.
Outbound messaging allows you to pool and reuse JMS sessions and connections when sending messages. In addition JCA takes care of associating inbound and outbound messaging with the same local transaction or XA.
This is very useful if you are inside either a Servlet or EJB type environemnt where you want to send messages from different threads, but don't want to create & close a connection, session, producer for each send.
JMS is designed for high performance message exchange. It makes heavy use of asynchronous message exchange to boost performance compared to synchronous request/response type systems.However creating and closing connections, sessions, producers is an expensive operation - since each operation will often require a synchronous request/response with the message broker (e.g. for security checks etc). So where possible JMS resources like connections, sessions, producers, consumers should be setup once on startup and reused/pooled. Then a send or receive is a blazingly fast operation.
<beans>
<!-- ActiveMQ -->
<bean id="broker" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="classpath:org/jencks/samples/outbound/broker.xml"/>
</bean>
<bean id="jmsResourceAdapter" class="org.apache.activemq.ra.ActiveMQResourceAdapter">
<property name="serverUrl" value="tcp://localhost:51616"/>
</bean>
<bean id="jmsQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="queue"/>
<property name="jndiEnvironment">
<props>
<prop key="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</prop>
<prop key="java.naming.provider.url">tcp://localhost:51616</prop>
<prop key="queue.queue">MyQueue</prop>
</props>
</property>
</bean>
<!-- Transaction manager-->
<bean id="transactionManager" class="org.jencks.factory.TransactionManagerFactoryBean"/>
<!-- Connection Manager -->
<bean id="connectionManager" class="org.jencks.factory.ConnectionManagerFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- JMS Managed Connection Factory -->
<bean id="jmsManagedConnectionFactory" class="org.apache.activemq.ra.ActiveMQManagedConnectionFactory">
<property name="resourceAdapter" ref="jmsResourceAdapter"/>
</bean>
<!-- JMS Connection Factory -->
<bean id="jmsConnectionFactory" class="org.jencks.factory.ConnectionFactoryFactoryBean">
<property name="managedConnectionFactory" ref="jmsManagedConnectionFactory"/>
<property name="connectionManager" ref="connectionManager"/>
</bean>
</beans>
Important to nate that the inbound and outbound config MUST match up.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment