Caching Strategy
Relevant source files
The following files were used as context for generating this wiki page:
- zheng-common/src/main/java/com/zheng/common/util/RedisUtil.java
- zheng-common/src/main/java/com/zheng/common/util/EhCacheUtil.java
- zheng-upms/zheng-upms-server/src/main/resources/ehcache.xml
- zheng-upms/zheng-upms-server/src/main/resources/shiro-ehcache.xml
- zheng-common/pom.xml
- zheng-cms/zheng-cms-rpc-service/src/main/java/com/zheng/cms/rpc/mapper/CmsArticleExtMapper.xml
- zheng-cms/zheng-cms-web/src/main/resources/ehcache.xml
- zheng-cms/zheng-cms-admin/src/main/resources/ehcache.xml
The zheng project employs a multi-layered caching strategy to enhance performance and reduce database load. The primary caching technologies are Ehcache for in-process, first-level caching and Redis for distributed, second-level caching. This approach provides fast access to frequently used data at both the local application level and across the distributed system.
Caching is integrated at various levels, including the data access layer with MyBatis, the security layer with Apache Shiro, and for general-purpose application data via dedicated utility classes.
Caching Technologies
The project relies on several key libraries for its caching implementation, all defined within the zheng-common module.
| Group ID | Artifact ID | Version | Description |
|---|---|---|---|
net.sf.ehcache | ehcache | 2.10.0 | The core Ehcache library for in-process caching. |
org.mybatis | mybatis-ehcache | 1.0.0 | Adapter for integrating Ehcache as a second-level cache in MyBatis. |
redis.clients | jedis | 2.9.0 | A client library for communicating with the Redis server. |
org.springframework.data | spring-data-redis | 1.7.5.RELEASE | Provides Spring framework integration and abstractions for Redis. |
org.springframework.session | spring-session-data-redis | 1.3.0.RELEASE | Manages user sessions with Redis, enabling distributed sessions. |
Sources: zheng-common/pom.xml:83-93, 134-142, 61-64
Caching Architecture
The system uses a two-tier cache-aside pattern. When an application needs data, it first checks the local Ehcache (L1). If the data is not found, it proceeds to check the distributed Redis cache (L2). If it's a miss in both caches, the application queries the primary database. The retrieved data is then written back to both Redis and Ehcache to serve future requests.
This diagram illustrates the data retrieval flow within the caching architecture.
Ehcache Implementation
Ehcache serves as the fast, in-memory, in-process (L1) cache. It is used for general application caching, as a second-level cache for MyBatis, and for caching security data for Shiro.
Configuration
Each module that utilizes Ehcache has its own ehcache.xml configuration file. This allows for tailored caching policies per module.
A typical configuration defines a diskStore path and one or more named cache regions.
Example Configuration from zheng-upms-server:
<ehcache>
<diskStore path="java.io.tmpdir/zheng-upms-server/ehcache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<cache
name="zheng-upms-server-ehcache"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="300"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</cache>
</ehcache>
Sources: zheng-upms/zheng-upms-server/src/main/resources/ehcache.xml
Key configuration parameters include:
| Parameter | Description | Example Value |
|---|---|---|
diskStore path | Directory on disk for storing overflow and persistent cache data. Each module uses a unique path (e.g., .../zheng-cms-web/ehcache). | java.io.tmpdir/zheng-upms-server/ehcache |
maxElementsInMemory / maxEntriesLocalHeap | The maximum number of cache entries to store in memory. | 10000 |
eternal | If true, elements are immortal and ignore timeToIdle and timeToLive. | false |
timeToIdleSeconds (TTI) | The maximum time an element can exist in the cache without being accessed. | 120 |
timeToLiveSeconds (TTL) | The maximum time an element can exist in the cache, regardless of access. | 120 (default), 300 (named cache) |
memoryStoreEvictionPolicy | The algorithm used to evict elements when maxElementsInMemory is reached. | LRU (Least Recently Used) |
persistence strategy | Defines how the cache persists to disk. | localTempSwap |
Sources: zheng-upms/zheng-upms-server/src/main/resources/ehcache.xml:2-20, zheng-cms/zheng-cms-web/src/main/resources/ehcache.xml:2-20, zheng-cms/zheng-cms-admin/src/main/resources/ehcache.xml:2-20
MyBatis Second-Level Cache
The project configures Ehcache as a second-level cache for MyBatis, which caches query results for mapper namespaces. This is enabled by adding a <cache> tag within a MyBatis mapper XML file.
The CmsArticleExtMapper.xml file uses LoggingEhcache, which is an Ehcache wrapper that adds logging for cache events.
<!-- Caching is enabled for this mapper namespace -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
Sources: zheng-cms/zheng-cms-rpc-service/src/main/java/com/zheng/cms/rpc/mapper/CmsArticleExtMapper.xml:65-66
Shiro Integration
Apache Shiro is configured to use Ehcache to cache authentication, authorization, and session data. This significantly improves performance by reducing repeated lookups for permissions and active sessions. The configuration is specified in shiro-ehcache.xml.
| Cache Name | Description |
|---|---|
shiro-activeSessionCache | Caches active user sessions. |
shiro-authenticationCache | Caches authentication information for users. |
shiro-authorizationCache | Caches authorization information (roles and permissions) for users. |
passwordRetryCache | Caches password retry attempts to prevent brute-force attacks. |
Sources: zheng-upms/zheng-upms-server/src/main/resources/shiro-ehcache.xml:14-41
Redis Implementation
Redis acts as the distributed (L2) cache, providing a shared cache for all application instances. It is also used for session management.
RedisUtil Class
Interaction with Redis is centralized through the RedisUtil class. This is a static utility class that wraps a RedisTemplate instance provided by Spring's spring-data-redis module. The RedisTemplate is injected into a static field, allowing for easy, application-wide access to Redis operations without needing to inject the utility class itself.
This diagram shows the structure of the RedisUtil class.
Sources: [zheng-common/src/main/java/com/zheng/common/util/RedisUtil.java]
The class provides a comprehensive set of methods for common Redis operations:
| Method Signature | Description |
|---|---|
get(String key) | Retrieves a value from Redis by its key. |
set(String key, Object value) | Sets a key-value pair with no expiration. |
set(String key, Object value, long expire) | Sets a key-value pair with a specified expiration time in seconds. |
del(String key) | Deletes one or more keys. |
hget(String key, String field) | Gets the value of a hash field. |
hset(String key, String field, Object value) | Sets the value of a hash field. |
hdel(String key, Object... field) | Deletes one or more hash fields. |
expire(String key, long expire) | Sets an expiration time on a key. |
getExpire(String key) | Gets the remaining time to live of a key. |
Sources: zheng-common/src/main/java/com/zheng/common/util/RedisUtil.java:34-191
Summary
The zheng project's caching strategy is a well-defined, two-layer system that leverages the strengths of both Ehcache and Redis. Ehcache provides extremely fast, local caching for individual application instances, with specific integrations for MyBatis and Shiro to optimize database and security operations. Redis complements this by providing a robust, distributed cache and session store, ensuring data consistency and availability across a scaled environment. This dual-cache architecture is a core component for achieving high performance and scalability.