This article has been updated to let you how to configure Stateful EJB Caches for your applications running on the latest version of WildFly application server.
What is a Stateful cache
Stateful session beans are conversational components that preserve their state contained in instance variables. Each stateful bean that is instantiated is stored in a cache, which is a memory area of the EJB container.
No need for Clustered Session Beans?
If you don’t need to have clustered Session Beans, then check this article to learn how to enable/disable it: How to disable passivation for SFSB in WildFly
By default, an HA configuration of the application server contains two caches configuration:
- simple: This a cache implementation using in-memory storage and eager expiration. It’s the default for non-clustered (ha) profiles.
- distributable: This is the cache which, by default, provides high-availability of SFSB state.
Here is the core section of the ejb3 subsystem:
<subsystem xmlns="urn:jboss:domain:ejb3:10.0"> <!-- . . . --> <caches> <simple-cache name="simple"/> <distributable-cache name="distributable"/> </caches> </subsystem>
In order to switch between the available Caches, you can use the @org.jboss.ejb3.annotation.Cache with the Cache name:
import org.jboss.ejb3.annotation.Cache; import jakarta.ejb.Stateful; @Stateful @Cache("distributable") public class SampleSFSB { int i=1; public int counter() { i++; return i; } }
Please note that to use the @Cache annotation you need to add the following dependency to your project:
<dependency> <groupId>org.jboss.ejb3</groupId> <artifactId>jboss-ejb3-ext-api</artifactId> <version>2.3.0.Final</version> <scope>provided</scope> </dependency>
Adding a custom Stateful Cache
In this paragraph, we will learn how to add a new Cache definition to the EJB subsystem which is backed by an infinispan Cache Container. Finally, please note that we will use the distributable-ejb subsystem available in WildFly 27 as a glue between the ejb subsystem and the infinispan subsystem.
Firstly, let’s add a new Distributed Cache to Infinispan named “custom-dist” with a number of owners = 2:
/subsystem=infinispan/cache-container=ejb/distributed-cache=custom-dist:add(owners=2)
Next, let’s set some custom attributes to our cache. For example, we will set the interval attribute to 0 and the isolation value to SERIALIZABLE:
/subsystem=infinispan/cache-container=ejb/distributed-cache=custom-dist/component=expiration:write-attribute(name=interval,value=0) /subsystem=infinispan/cache-container=ejb/distributed-cache=custom-dist/component=locking:write-attribute(name=isolation,value=SERIALIZABLE)
You need to reload the configuration for changes to take effect. Next, you will see the “custom-dist” distributed-cache enlisted in your “ejb” Cache Container:
<subsystem xmlns="urn:jboss:domain:infinispan:13.0"> <cache-container name="ejb" default-cache="dist" marshaller="PROTOSTREAM" aliases="sfsb" modules="org.wildfly.clustering.ejb.infinispan"> <transport lock-timeout="60000"/> <replicated-cache name="client-mappings"> <expiration interval="0"/> </replicated-cache> <distributed-cache name="dist"> <locking isolation="REPEATABLE_READ"/> <transaction mode="BATCH"/> <expiration interval="0"/> <file-store/> </distributed-cache> <distributed-cache name="custom-dist" owners="2"> <locking isolation="SERIALIZABLE"/> <expiration interval="0"/> </distributed-cache> </cache-container> <!-- ....--> </subsystem>
Next, it’s time to register the “custom-dist” cache in your distributable-ejb subsystem:
/subsystem=distributable-ejb/infinispan-bean-management=custom:add(cache=custom-dist,max-active-beans=1000,cache-container=ejb)
The default-bean-management cache remains the “default”. However, now it’s available also the “custom” bean management name:
<subsystem xmlns="urn:jboss:domain:distributable-ejb:1.0" default-bean-management="default"> <infinispan-bean-management name="default" cache-container="ejb" cache="dist" max-active-beans="10000"/> <infinispan-bean-management name="custom" cache-container="ejb" cache="custom-dist" max-active-beans="1000"/> <infinispan-client-mappings-registry cache-container="ejb" cache="client-mappings"/> </subsystem>
Finally, let’s add a new ejb3 cache which references the infinispan “custom” bean-management:
/subsystem=ejb3/distributable-cache=custom-distributable:add(bean-management=custom)
This is the expected outcome in your ejb3 configuration:
<subsystem xmlns="urn:jboss:domain:ejb3:10.0"> <!-- ....--> <caches> <simple-cache name="simple"/> <distributable-cache name="distributable"/> <distributable-cache name="custom-distributable" bean-management="custom"/> </caches> <!-- ....--> </subsystem>
The Custom Cache configuration is now complete. In order to use it, reference the ejb3 “custom-distributable” cache from your EJBs. For example:
import org.jboss.ejb3.annotation.Cache; import jakarta.ejb.Stateful; @Stateful @Cache("custom-distributable") public class SampleSFSB { int i=1; public int counter() { i++; return i; } }
As an alternative, you can refer to your EJB Stateful cache in the jboss-ejb3.xml. Here is an excerpt of it:
<c:cache> <ejb-name>*</ejb-name> <c:cache-ref>custom-distributable</c:cache-ref> </c:cache>
Conclusion
In this tutorial we have covered how to configure a custom Cache for Stateful Session Beans on the latest release of WildFly. You can find the source code for this article: https://github.com/fmarchioni/mastertheboss/tree/master/ejb/ejb-cache