Beyond Redis: When to Choose EhCache for Java In‑Process Caching

With hardware costs dropping, many default to Redis for caching, but it isn’t always optimal; this article examines EhCache—a pure‑Java, in‑process cache—covering its architecture, eviction policies, API and XML configurations, and step‑by‑step Spring Boot integration, helping you decide when to prefer it.

Senior Brother's Insights
Senior Brother's Insights
Senior Brother's Insights
Beyond Redis: When to Choose EhCache for Java In‑Process Caching

Background

As hardware becomes cheaper, developers often rely on adding more machines instead of optimizing code, leading to a default choice of Redis for caching. However, Redis is not always the most efficient solution, especially for single‑process, high‑throughput scenarios.

What Is EhCache?

EhCache is a pure‑Java, in‑process caching framework that operates directly inside the JVM, offering fast, lightweight caching. It is the default cache provider for Hibernate and is supported by Spring Boot through Spring’s cache abstraction.

Key Features

Simple and fast with multiple caching strategies.

Two‑level storage: memory and disk, alleviating capacity concerns.

Disk persistence writes cache data during JVM shutdown.

Supports distributed caching via RMI, JGroups, JMS, or Cache Server.

Provides listener interfaces for cache and cache manager events.

Allows multiple cache manager instances and multiple cache regions per instance.

Advantages and Limitations

Advantages include low latency due to in‑process operation and ease of use. Limitations are significant disk usage for the DiskCache tier and lack of strong data safety guarantees; abrupt JVM termination can cause conflicts, and cache rebuilding may be required.

EhCache vs. Redis

EhCache operates within the JVM, offering higher speed for single‑node applications, while Redis accesses a separate service over sockets, providing better support for distributed clusters and larger cache sizes. Choose EhCache for monolithic, high‑frequency access scenarios; choose Redis for large, shared, or distributed caches.

Architecture Overview

The core components are CacheManager, Cache, and Element. CacheManager creates and manages caches; each Cache holds multiple Elements, which are the actual cached entries.

Cache replication, in‑process APIs, and network APIs provide mechanisms for distributed caching, JSR/JMX compatibility, and RESTful/JMS access respectively.

Eviction Strategies

EhCache supports three eviction algorithms:

FIFO – removes the oldest entries first.

LRU – removes the least recently used entries.

LFU – removes the least frequently used entries.

It uses a lazy eviction mechanism, storing timestamps with each entry and checking TTL on reads.

Practical Usage

API‑Based Configuration

Add the Maven dependency:

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.9.6</version>
</dependency>

Example Java test class:

public class EhCacheTest {

    @Test
    public void test() {
        // 1. Build a CacheManager
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
            .withCache("preConfigured",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                    ResourcePoolsBuilder.heap(100)).build())
            .build(true);

        Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);
        System.out.println("Pre‑configured cache: " + preConfigured);

        // 2. Create a new cache
        Cache<Long, String> myCache = cacheManager.createCache("myCache",
            CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                ResourcePoolsBuilder.heap(100)).build());
        myCache.put(1L, "da one!");
        String value = myCache.get(1L);
        System.out.println("Value for key 1L: " + value);

        cacheManager.close();
    }
}

XML‑Based Configuration

Place ehcache.xml under src/main/resources:

<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xsi:schemaLocation='http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd'>

    <cache alias="foo">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.String</value-type>
        <resources>
            <heap unit="entries">20</heap>
            <offheap unit="MB">10</offheap>
        </resources>
    </cache>

    <cache-template name="myDefaults">
        <key-type>java.lang.Long</key-type>
        <value-type>java.lang.String</value-type>
        <heap unit="entries">200</heap>
    </cache-template>

    <cache alias="bar" uses-template="myDefaults">
        <key-type>java.lang.Number</key-type>
    </cache>

    <cache alias="simpleCache" uses-template="myDefaults"/>

The XML defines a regular cache, a template for reuse, and a cache that inherits the template while overriding the key type.

Spring Boot Integration

Add the starter and EhCache dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.9.6</version>
</dependency>

Configure the cache location in application.properties: spring.cache.ehcache.config=ehcache.xml Enable caching in the main class:

@EnableCaching
@SpringBootApplication
public class SpringBootMainApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootMainApplication.class, args);
    }
}

Define a cached entity:

@Data
public class Person {
    private int id;
    private String name;
    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

Service interface and implementation using @Cacheable:

public interface PersonService {
    Person getById(int id);
}

@Service("personService")
public class PersonServiceImpl implements PersonService {
    @Cacheable(value = "personCache", key = "#id")
    @Override
    public Person getById(int id) {
        if (id == 1) return new Person(1, "Tom");
        else if (id == 2) return new Person(2, "Jim");
        return new Person(3, "Other");
    }
}

Unit test demonstrating cache hits:

@SpringBootTest
class PersonServiceTest {
    @Resource
    private PersonService personService;

    @Test
    void testCache() throws InterruptedException {
        personService.getById(1); // first call, hits method
        personService.getById(1); // second call, served from cache
    }
}

Log output shows the method is invoked only once, confirming caching works.

Conclusion

The article provides an entry‑level guide to EhCache, covering its concepts, eviction policies, API and XML configuration, and Spring Boot integration. While EhCache excels in single‑process, high‑throughput scenarios, it lacks robust distributed features, so for large‑scale or clustered environments Redis remains preferable.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavarediscachingSpring BootCache EvictionEhcache
Senior Brother's Insights
Written by

Senior Brother's Insights

A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.