WildFly custom caches configuration for Stateful Beans

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

Found the article helpful? if so please follow us on Socials