Buscar este blog

miércoles, 27 de julio de 2016

Jboss - Spring - Infinispan cache

In a previous post I explained how to configure Hibernate Second Level Cache with Infinispan in a cluster enviroment, check here. Now I´ll show you how to configure a business cache with Spring, also with Infinispan in a JBoss Cluster enviroment.

When I talk about bussines cache I mean the service tier in a multi-tier JEE application. Usually one service (or use case) involves multiple accesses to database, even to multiple databases and remote services, so this kind of cache is complementary to Hibernate cache.

Spring Framework provides a cache abstraction, an infraestructure arround some spring-managed beans which delegates the cache management over a plugable cache container. In this case, this container will be Infinispan.


JBoss configuration

You need to use, at least, the HA profile (High Availability).

Similar to Hibernate, the cache container will be provided by JBoss. In this example I created a myCustomCache container, configured over UDP in order to share information over the cluster nodes.
/profile=ha/subsystem=infinispan/cache-container=myCustomCache:add(start=EAGER)
/profile=ha/subsystem=infinispan/cache-container=myCustomCache/transport=TRANSPORT:add(lock-timeout="60000", stack="udp", cluster="myCustomCache-cluster")


Application configuration

Spring config

Spring will use the cache container created previously to store and recover the cached objects. This container will be obtained via JNDI and injected in a bean of SpringEmbeddedCacheManager.
But this procedure has a problem, you can not define your own cache regions. When spring asks for a new cache region, if it yet not exists , the cache manager creates it with default values. In a cluster enviroment, as I tested, this is a local cache, so it will not be shared amongst the nodes.

In order to create custom regions, and declare them as distributables, you need to create your own extension of the SpringEmbeddedCacheManager. This class will read an internal infinispan configuration file, parse it and "add" the declared caches to the cache manager.

This is the CustomSpringEmbeddedCacheManager class:
public class CustomSpringEmbeddedCacheManager extends SpringEmbeddedCacheManager implements InitializingBean {
    private static Logger LOGGER = LoggerFactory.getLogger(CustomSpringEmbeddedCacheManager.class);

    private Resource infinispanXMLFile;

 public void setInfinispanXMLFile(final Resource infinispanXMLFile) {
        this.infinispanXMLFile = infinispanXMLFile;
    }
 
 
    public CustomSpringEmbeddedCacheManager(final EmbeddedCacheManager nativeCacheManager) {
        super(nativeCacheManager);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
     final EmbeddedCacheManager cacheManager = getNativeCacheManager();
   
        final ParserRegistry parserRegistry = new ParserRegistry(Thread.currentThread().getContextClassLoader());
        final ConfigurationBuilderHolder configurationBuilderHolder = parserRegistry.parse(infinispanXMLFile.getInputStream());
        final Map<String, ConfigurationBuilder> namedConfigs = configurationBuilderHolder.getNamedConfigurationBuilders();
      
        for (final Map.Entry<String, ConfigurationBuilder> entry : namedConfigs.entrySet()) {
            if (cacheManager.cacheExists(entry.getKey())) {
                LOGGER.trace("Eliminando cache {}", entry.getKey());
                cacheManager.removeCache(entry.getKey());
            }

            LOGGER.trace("Definiendo nueva cache {}", entry.getKey());
            cacheManager.defineConfiguration(entry.getKey(), entry.getValue().build());
        }
    } 
}

Now, in your application context, you need to obtain de Infinispan cache manager and configure the spring cache manager.
<jee:jndi-lookup id="nativeCacheManager" expected-type="org.infinispan.manager.CacheContainer" jndi-name="java:jboss/infinispan/container/myCustomCache"/>
          
<bean id="cacheManager"  class="es.cixtec.arq.jboss.CustomSpringEmbeddedCacheManager">
  <constructor-arg>
   <ref bean="nativeCacheManager"/>
  </constructor-arg>
  <property name="infinispanXMLFile" value="classpath:infinispan-business.xml"/>
 </bean>

<cache:annotation-driven />

Note that you need to use a internal infinispan configuration file, in this case infinispan-business.xml, located in the classpath (maven resources directory):
<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="urn:infinispan:config:5.1 http://www.infinispan.org/schemas/infinispan-config-5.1.xsd"
 xmlns="urn:infinispan:config:5.2">

 <namedCache name="someBusiness">
  <eviction strategy="LRU" maxEntries="10000" />
  <expiration lifespan="60000" maxIdle="60000" />
  <clustering mode="replication">
   <sync replTimeout="10000" />
  </clustering>
 </namedCache>

</infinispan>

Dependency config

You need to import the following dependencys:
<dependencies>

 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>3.2.17.RELEASE</version>
 </dependency>
  
 <dependency>
  <groupId>org.infinispan</groupId>
  <artifactId>infinispan-core</artifactId>
  <version>5.2.15.Final</version>
  <scope>provided</scope>
 </dependency>
 
</dependencies>

Documentation

Available doc:

No hay comentarios:

Publicar un comentario