10.7. Resource Pooling

BlazeDS interacts with and interfaces with message queues and topics, databases and Java enterprise infrastructure. Many of these external systems and libraries, such as messaging infrastructure, database connections and stateless business services, lend themselves to pooling. When resources are pooled, they are shared over multiple clients.

Usually the creation and initialization, as well as the cleanup and garbage collection, of a resource is expensive. If such a resource is reused often and each time it is used the interaction time is not substantially long, then it is a good candidate for pooling.

In typical enterprise-grade Flex and BlazeDS applications, interaction with a database is an important and necessary part of the application. If such applications utilize near real-time updates, then JMS and messaging infrastructure also become very relevant.

In this section, I discuss JDBC connection and JMS resource pooling to illustrate the use of resource pooling to enhance Flex and BlazeDS application performance. Much of the discussion may not even refer to BlazeDS directly. However, such is typically the case with resource pooling, where much of the activity happens quietly under the hood, without impacting the application code at all.

I start with JDBC connection pooling.

10.7.1. JDBC Connection Pooling

It is always expensive to establish database connections. The process of object creation, transfer of messages across the network for authentication and login, and then initialization on both the database and the application ends is typically intensive. Therefore, it makes sense to create a JDBC connection pool on startup and then allocate connections from this pool. When work using a connection allocated from the pool is done, the connection is returned to the pool.

BlazeDS is a Java Servlets web application and so is deployed in an application server that includes a Servlet container. Popular open source choices for deploying BlazeDS are Apache Tomcat and JBoss. Both these application servers, and almost every other available in the market today, support JDBC connection pooling by default.

I will explore JDBC connection pooling in both Apache Tomcat and JBoss. Let's start with Tomcat. In Tomcat, Apache Commons DBCP is used by default for JDBC connection pooling. You can read more about the Apache Commons DBCP connection pool at http://commons.apache.org/dbcp/. To use DBCP, you need to configure it with a JNDI DataSource. In Tomcat, you configure this in the server.xml configuration file that resides in the conf directory of your Tomcat installation. Add the following lines to server.xml:

<Context path="/dbcp" docBase="dbcp" debug="5"
reloadable="true" crossContext="true">

<Resource name="jdbc/YetAnotherDB" auth="Container"
   type="javax.sql.DataSource" removeAbandoned="true"
   removeAbandonedTimeout="30" maxActive="100"
   maxIdle="30" maxWait="10000" username="<provide the user name>"
   password="<provide the password>"
   driverClassName="com.mysql.jdbc.Driver"
   url="jdbc:mysql://localhost/yadb"/>

</Context>

In addition, add the following lines to web.xml so that the JNDI can resolve this reference:

<resource-ref>
      <description> DB Connection Pooling</description>
      <res-ref-name> jdbc/YetAnotherDB</res-ref-name>
      <res-type> javax.sql.DataSource</res-type>
      <res-auth> Container</res-auth>
  </resource-ref>

The preceding configuration for the DataSource in server.xml assumes the underlying database is MySQL. If that's not the case, then please replace the driverClassName and URI with the appropriate values for your target database. Also, don't forget to add the particular database's JDBC driver-related classes in Tomcat's classpath. Once the DataSource is configured in server.xml, you can create a connection using this DataSource as the connection factory. The code for getting hold of a JDBC connection then could involve referencing the DataSource as follows:

Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
    datasource = (DataSource) envCtx.lookup("jdbc/YetAnotherDB");

Once you have obtained a reference to the DataSource, you can call the getConnection method of the DataSource to get a connection to the database. A connection obtained in this manner is a pooled connection. Therefore, the first time such a connection is created, but the next time it's obtained from the pool.

You probably want to optimize this further by instantiating the DataSource handle only once on startup for a web application. In a Java web application the ServletContext has application wide visibility, and instantiating something within a ServletContextListener could make it to run only once on application initialization. Therefore, you could create a class as follows:

Package somePackage.someSubPackage;
public class JDBCPoolingListener implements
ServletContextListener{
 public void contextInitialized
  (ServletContextEvent sce){

  try {

// Obtain our environment naming context
    Context envCtx = (Context) new InitialContext().
    lookup("java:comp/env");

    // Look up our data source
    DataSource  ds = (DataSource) envCtx.lookup
       ("jdbc/YetAnotherDB");

    sce.getServletContext().setAttribute
      ("JDBCPool", ds);
   } catch(NamingException e){ e.printStackTrace();
  }
 }
 public void contextDestroyed(ServletContextEvent
 sce){
 }
}

To use this listener, you can configure it in web.xml as follows:

<listener>
        <listener-class> somePackage.someSubPackage.JDBCPoolingListener</listener-class>
</listener>

That is all it takes to leverage JDBC connection pooling in Tomcat. Next, let's briefly explore how a pooled connection is configured and setup in JBoss.

A DataSource can be created in JBoss by creating a configuration file with a "-ds.xml" naming convention. For MySQL you create a file called: mysql-ds.xml. Deploy mysql-ds.xml in JBoss by copying it over to the /server/default/deploy folder of the JBoss installation. The contents of mysql-ds.xml could be as follows:

<datasources>
    <local-tx-datasource>
        <jndi-name>jdbc/YetAnotherDB</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/yadb</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>provide the user name</user-name>
        <password><provide the password></password>
    </local-tx-datasource>
</datasources>

I will skip the details on how this pooled connection can be used in an application that is deployed in JBoss. By now, though, you must be convinced that database connection pooling is effortless and could help make your application more scalable.

The next topic briefly explores pooling of JMS resources.

10.7.2. JMS Resource Pooling

JMS promotes the principle of instantiation of a number of components on startup and reuse of these components subsequently. Such JMS components are:

  • Connection

  • Session

  • MessageProducer

  • MessageConsumer

As with database connections, creating and destroying JMS resources have overhead. Therefore, pooling JMS resources is advisable for optimal resource utilization and performance boost.

Next, you will briefly learn two techniques that pool and cache JMS resources and increase message processing performance. These involve:

  • The use of Camel (http://camel.apache.org/) for bean integration

  • The use of Spring framework's (http://springsource.com) AbstractMessageListenerContainer and its subclasses that provide an asynchronous message consumer that caches JMS consumers, connections, and sessions

Although the following discussion may apply to many JMS providers, they are especially useful in the context of the open source JMS provider ActiveMQ. ActiveMQ can be used with almost any Java application server, including Tomcat, JBoss, and Jetty.

Before we go to the two recommendations I listed, let me start by suggesting the use of Java Connector Architecture (or JCA) on the server to wire up JMS resources. JCA is a Java EE standard for integrating enterprise information systems with Java application servers. You can read more about it online at http://java.sun.com/j2ee/connector/overview.html.

JCA supports the pooling of JMS connections, session, and message listeners. It introduces efficiencies by supporting thread pooling and parallel message processing. JCA works with any JMS provider that has a JCA Resource Adapter. ActiveMQ JMS infrastructure is typically configured in JBoss as a JCA Resource.

Next, let's explore the two recommendations that increase JMS message processing performance.

10.7.3. Bind Messaging to the Beans Using Camel

This technique recommends binding the messages to your beans instead of directly using the JMS API.

Apache Camel is an open source integration framework that lets you implement routing and mediation rules in either of the following:

  • A Java-based domain-specific language (DSL)

  • Scala DSL

  • Spring framework XML configuration

The Camel project started in 2007 with the goal of implementing all the integration patterns described in the book Enterprise Integration Patterns: Designing, Building and Deploying Messaging Solutions by Gregor Hohpe and Bobby Woolfe (Addison Wesley, 2003). The Camel project is part of the Apache ActiveMQ project.

Camel defines a bean binding mechanism in which it specifies which methods are invoked on a particular message and how the message is translated into the parameters for the method when it is invoked. You can avoid the JMS API and directly leverage bean binding to consume your messages.

Explaining Camel in detail is beyond the scope of this book, but I encourage you to explore it further to understand how you could utilize the enterprise integration patterns in your applications to drive efficiency in your messaging systems.

10.7.4. Using Spring's Support for Message Listener Containers

If you are totally unfamiliar with the open source Spring framework, this section may sound alien. So possibly reading Chapter 5, which covers BlazeDS and Spring integration, may be a better place to start. Although Chapter 5 is not an introduction to the Spring framework itself, fundamentals of that technology are covered there.

In the world of EJBs, Message Driven Beans (MDBs) serve the purpose of message listeners. So when JMS and EJBs are used together, it makes sense to leverage the MDBs as message consumers. Spring extended this message listener concept to POJOs, introducing what they called a Message Driven POJO (or MDP for short).

A message listener container is used to receive messages from a JMS message queue. Incoming messages drive the message listener as they arrive. The message listener container serves as an intermediary between a message producer and an MDP. The container also provides additional services such as registration, transaction, resource acquisition, and release and exception handling. The Spring framework comes with three message listener containers. These three are:

  • SimpleMessageListenerContainer

  • DefaultMessageListenerContainer

  • ServerSessionMessageListenerContainer

The DefaultMessageListenerContainer is the most popular of the three. It allows for the creation of a few JMS sessions on startup and then adapts dynamically at runtime. It can work with external transaction managers. JMS resources like sessions and message consumers are cached and pooled.

If your technology stack includes the Spring framework and you need messaging in your application as well, then you may be better off leveraging the Spring message listener containers to make your applications superior in performance to its counterparts that deal with the raw JMS API.

This section emphasized resource pooling. The next one focuses on optimal utilization of resources on both sides of the wire: the client and the server.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.81.43