Chapter 22. Caching
Database is the primary bottleneck in most enterprise applications, and the least scalable tier of the runtime environment. We can dramatically improve the application performance by reducing the number of times the database is accessed.
A well-designed Seam application features a rich and multi-layered caching strategy that impacts every layer of the application, including:
- A cache for the database. This is vital, but cannot scale like a cache in the application tier.
- A secondary cache of data from the database, provided by the ORM solution (Hibernate, or another JPA implementation). In a clustered environment, it can be very expensive to effectively implement a cache whose data is transactionally consistent with the database and the rest of the cluster. Therefore, secondary cache is best used to store data that is rarely updated, and shared between many users. In traditional stateless architectures, secondary cache is often used (ineffectively) to store conversational state.
- The Seam conversational context, which is a cache of conversational state. Components in the conversation context, store the state related to the current user interaction.
- The Seam-managed persistence context, which acts as a cache of data read in the current conversation. (An Enterprise JavaBean [EJB] container-managed persistence context associated with a conversation-scoped stateful session bean can be used instead of a Seam-managed persistence context.) Seam optimizes the replication of Seam-managed persistence contexts in a clustered environment, and optimistic locking provides sufficient transactional consistency with the database. The performance implications of this cache are minimal, unless you read thousands of objects into a single persistence context.
- The Seam application context, which can be used to cache non-transactional state. The state held in the Seam application context is not visible to other nodes in the cluster.
- The Seam
cacheProvidercomponent within the application, which integrates Infinispan, or Ehcache into the Seam environment. The state held in the SeamcacheProvidercomponent is visible to other nodes in the cluster if your cache is configured to run in clustered mode. - Seam cache that renders fragments of a JSF page. Unlike the ORM secondary cache, this cache is not automatically invalidated when data is updated. You have to write application code to perform explicit invalidation of this cache, or set appropriate expiry policies.
For more information about secondary cache, refer to the documentation of your ORM solution, since this can be quite complex.
This chapter discusses the use of caching through the
cacheProvider component, and caching as stored page fragments through the <s:cache> control.
22.1. Using Caching in Seam
The built-in
cacheProvider component manages an instance of:
- Infinispan 5.x (suitable for use in Red Hat JBoss Enterprise Application Platform and other containers)
org.infninispan.tree.TreeCache- EHCache (suitable for use in any container)
net.sf.ehcache.CacheManager
Note
The built-in cacheProvider component that uses Infinispan Tree module as JBoss Cache successor is not supported since JBoss Web Framework Kit 2.4.0.
You can add an immutable Java object in the cache. The immutable object is stored in the cache and replicated across the cluster (assuming that replication is supported and enabled). To add mutable objects to the cache, read the documentation of the underlying caching project to know how to notify the cache of changes to the cache.
To use the
cacheProvider component, include the jars of cache implementation in your project:
- Infinispan 5.x
infinispan-core.jar- Infinispan Core 5.2.x.Finalinfinispan-tree.jar- Infinispan TreeCache 5.2.x.Finaljgroups.jar- JGroups 3.2
- EHCache
ehcache.jar- EHCache 1.2.3
For an EAR deployment of Seam, we recommend you to add the infinispan jars, and configuration directly into the EAR.
Note
JBoss Enterprise Application Platform 6 already provides Infinispan and JGroups jars. Turn ON the dependencies in your deployment file or modify
META-INF/Manifest.mf file to get the dependencies. Refer to the relevant JBoss Enterprise Application Platform documentation for further information.
You can find a sample cache configuration at:
examples/blog/blog-web/src/main/resources/infinispan.xml.
Ehcache runs in its default configuration without a configuration file.
To alter the configuration file in use, configure your cache in
components.xml:
<components xmlns="http://jboss.org/schema/seam/components" xmlns:cache="http://jboss.org/schema/seam/cache"> <cache:infinispan-cache-provider configuration="infinispan.xml" /> </components>
Now you can inject the cache into any Seam component:
@Name("chatroomUsers") @Scope(ScopeType.STATELESS) public class ChatroomUsers { @In CacheProvider cacheProvider; @Unwrap public Set<String> getUsers() throws CacheException { Set<String> userList = (Set<String>) cacheProvider.get("chatroom", "userList"); if (userList==null) { userList = new HashSet<String>(); cacheProvider.put("chatroom", "userList", userList); } return userList; } }
To make multiple cache configurations available to your application, use
components.xml to configure multiple cache providers:
<components xmlns="http://jboss.org/schema/seam/components" xmlns:cache="http://jboss.org/schema/seam/cache"> <cache:infinispan-cache-provider name="myCache" configuration="myown/cache.xml"/> <cache:infinispan-cache-provider name="myOtherCache" configuration="myother/cache.xml"/> </components>