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