Backend Development 10 min read

Understanding Caching in Java with Spring Cache, Ehcache, and Redis

This article explains the concept of caching in Java, the importance of reducing database I/O, introduces Spring Cache annotations and their limitations, demonstrates conditional caching with code examples, and provides configuration details for integrating Ehcache and Redis as cache providers.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Understanding Caching in Java with Spring Cache, Ehcache, and Redis

Caching is a widely used technique to improve performance by storing frequently accessed objects in memory, reducing the need to recreate instances and lowering system overhead. In Java applications, caching helps alleviate the heavy load caused by frequent database queries, which account for over 80% of CRUD operations and can severely degrade performance due to disk I/O.

Different layers of a system architecture can employ caches to accelerate access, and the article includes diagrams illustrating cache roles at various levels.

Spring Cache offers a simple way to integrate popular cache frameworks such as Ehcache, Redis, and Memcached through annotations. While annotation‑based caching is convenient, it lacks flexible cache policies.

Cache policies include TTL (Time To Live) – the fixed lifespan of a cache entry regardless of access, and TTI (Time To Idle) – the period of inactivity after which an entry is evicted.

Conditional caching can be implemented using the @Cacheable , @CachePut , and @CacheEvict annotations with condition or unless expressions. Example snippets:

@Cacheable(value = "user", key = "#id", condition = "#id lt 10")
public User conditionFindById(final Long id)
@CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")
public User conditionSave(final User user)
@CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")
public User conditionSave2(final User user)
@CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'")
public User conditionDelete(final User user)

A combined example demonstrates CRUD operations with caching annotations:

@CachePut(value = "user", key = "#user.id")
    public User save(User user) {
        users.add(user);
        return user;
    }

    @CachePut(value = "user", key = "#user.id")
    public User update(User user) {
        users.remove(user);
        users.add(user);
        return user;
    }

    @CacheEvict(value = "user", key = "#user.id")
    public User delete(User user) {
        users.remove(user);
        return user;
    }

    @CacheEvict(value = "user", allEntries = true)
    public void deleteAll() {
        users.clear();
    }

    @Cacheable(value = "user", key = "#id")
    public User findById(final Long id) {
        System.out.println("cache miss, invoke find by id, id:" + id);
        for (User user : users) {
            if (user.getId().equals(id)) {
                return user;
            }
        }
        return null;
    }

Configuration for integrating Ehcache with Spring Cache involves adding the Ehcache dependency and defining beans in spring-ehcache.xml :

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>${ehcache.version}</version>
</dependency>
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation" value="classpath:xml/ehcache.xml"/>
</bean>

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="ehcacheManager"/>
    <property name="transactionAware" value="true"/>
</bean>

<cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>

For Redis integration, the required dependencies and bean definitions are provided in spring-redis.xml , including pool configuration, JedisConnectionFactory , RedisTemplate , and a RedisCacheManager with default expiration and specific cache lifetimes.

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.8.1.RELEASE</version>
</dependency>
... (additional dependencies) ...
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="${redis.pool.maxIdle}"/>
    ...
</bean>

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="${redis.master.ip}"/>
    <property name="port" value="${redis.master.port}"/>
    <property name="poolConfig" ref="jedisPoolConfig"/>
</bean>

<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" c:redisOperations-ref="redisTemplate">
    <property name="defaultExpiration" value="600"/>
    <property name="usePrefix" value="true"/>
    <property name="expires">
        <map key-type="java.lang.String" value-type="java.lang.Long">
            <entry key="halfHour" value="1800"/>
            <entry key="hour" value="3600"/>
            <entry key="oneDay" value="86400"/>
        </map>
    </property>
</bean>

<cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>

Only one cache configuration can be active at a time; the appropriate XML file is imported to select either Ehcache or Redis, though they can be combined (e.g., Ehcache as L1 and Redis as L2).

<import resource="classpath:spring/spring-ehcache.xml"/>
<!-- <import resource="classpath:spring/spring-redis.xml"/> -->

For more detailed usage and configuration, refer to the spring-shiro-training project.

JavaPerformanceRedisCachingAnnotationsSpring CacheEhcache
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

0 followers
Reader feedback

How this landed with the community

login 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.