Boosting Java Application Performance with Ehcache

Introduction to Ehcache

Ehcache is a tool used in Java to make programs run faster by storing and retrieving data more efficiently. It helps speed up applications by keeping frequently used information close at hand, reducing the need to fetch it repeatedly from the main data source.

What is Caching?

Ehcache is an open-source library used in Java for caching Java programs, specifically local and distributed caching in main memory or on the hard disk.

Why Ehcache?

Caching is mainly useful for the following scenarios- The same data is requested again and again (so-called hot spots), which have to be loaded from the database anew with each request. This data can be cached in the main memory of the server application (RAM) or on the client (browser cache). This reduces access times and the number of data transfers since the server does not have to repeatedly request data from the database and send it to the client.

Long-term or resource-intensive operations are often performed with specific parameters. Depending on the parameters, the result of the operation can be stored temporarily so that the server can send the result to the client without executing the operation.

Key Features

➡️ Simple Configuration: Ehcache can be easily configured using XML or programmatically.
➡️ Memory Management: Efficient use of memory with features like eviction policies and off-heap storage.
➡️ Caching Strategies: Support for various caching strategies, including time-based expiration, LRU (Least Recently Used), and more.
➡️ Concurrency Support: Thread-safe operations and support for concurrent access.
➡️ Listeners: Ability to register listeners to be notified of cache events.

Ehcache Architecture

🔹In-Memory Storage: Ehcache primarily operates in memory, which means cached data is stored in the application’s heap memory. This allows for fast read and write access.

🔹Cache Elements: Ehcache manages data in the form of key-value pairs, where the key is used for lookups, and the value is the cached data.

🔹Cache Managers: Cache managers are responsible for creating and managing caches. Multiple caches can coexist within a single cache manager, each with its configuration and characteristics.

Basic Usage

🔸Adding Dependencies: To use Ehcache in your Java project, add the Ehcache dependencies to your project’s build file. For example, in Maven:

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

🔸Configuring Ehcache: Ehcache can be configured using an XML file or programmatically. Here’s a basic XML configuration:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <cache name="myCache"
        maxEntriesLocalHeap="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        memoryStoreEvictionPolicy="LRU"/>
</ehcache>

To enable caching support in Spring Boot, we need a simple configuration class that must be annotated with

@EnableCaching. Up to this point, we don’t need to do anything more as the following code shows:

@Configuration
@EnableCaching
public class EhcacheConfig {
}

🔸Basic Cache Operations: Using Ehcache for caching involves simple operations, such as putting data into the cache, getting data from the cache, and removing data from the cache. Here’s an example:

@Service
public class CalculationService {
private final Logger LOG = LoggerFactory.getLogger(CalculationService.class);
public double areaOfCircle(int radius) {
LOG.info("calculate the area of a circle with a radius of {}", radius);
return Math.PI * Math.pow(radius, 2);
}
}
@Cacheable(value = "areaOfCircleCache", key = "#radius", condition = "#radius > 5")
public double areaOfCircle(int radius) {
LOG.info("calculate the area of a circle with a radius of {}", radius);
return Math.PI * Math.pow(radius, 2);
}

Related read: 19 Point Checklist: Starting a New Project in Spring Boot

Hire Skilled Java Developers to Bring Expertise and Efficiency to Your Team

Advanced Features

🔹Cache Eviction Strategies: To avoid inflated caches, you should, of course, have configured a meaningful eviction strategy. On the other hand, it is also possible to empty the cache based on requests. The following example shows how to remove all entries from the caches areaOfCircleCache and multiplyCache.

@CacheEvict(cacheNames = {"areaOfCircleCache", "multiplyCache"}, allEntries = true)
public void evictCache() {
LOG.info("Evict all cache entries...");
}

🔹Cache Listeners: Cache listeners allow you to respond to cache events, such as entries being added, updated, or removed. This can be useful for implementing custom logic when the cache state changes.
In the listener’s tag, we configure a CacheEventListener. The listener reacts to the following events:

  • A cache entry is placed in the cache (CREATED).
  • The validity of a cache entry has expired (EXPIRED).
  • A cache entry is evicted from the cache (EVICTED).

The specified CacheLogger class only logs the occurred cache event on the console:

public class CacheLogger implements CacheEventListener<Object, Object> {
private final Logger LOG = LoggerFactory.getLogger(CacheLogger.class);
@Override
public void onEvent(CacheEvent<?, ?> cacheEvent) {
LOG.info("Key: {} | EventType: {} | Old value: {} | New value: {}",
cacheEvent.getKey(), cacheEvent.getType(), cacheEvent.getOldValue(),
cacheEvent.getNewValue());
}
}

🔹CacheConfig: The @CacheConfig annotation allows us to define certain cache configurations at the class level. This is especially useful if certain cache settings are the same for all methods to be cached:

@Service
@CacheConfig(cacheNames = "studentCache")
public class StudentService {
// ...
@Cacheable
public Optional<Student> find(Long id) {
// ... 
}
@CachePut(key = "#result.id")
public Student create(String firstName, String lastName, String courseOfStudies) {
// …
}

Both the find() and create() methods use the studentCache cache in this example.

🔹CachePut: Methods annotated with @Cacheable are not executed again if a value already exists in the cache for the cache key. If the value does not exist in the cache, then the method is executed and places its value in the cache.

Now there is also the use case that we always want the method to be executed and its result to be placed in the cache. This is done using the @CachePut annotation, which has the same annotation parameters as @Cachable.

A possible scenario for using @CachePut is, for example, creating an entity object, as the following example shows:

@CachePut(cacheNames = "studentCache", key = "#result.id")
public Student create(String firstName, String lastName, String courseOfStudies) {
LOG.info("Creating student with firstName={}, lastName={} and courseOfStudies={}",
firstName, lastName, courseOfStudies);
long newId = ID_CREATOR.incrementAndGet();
Student newStudent = new Student(newId, firstName, lastName, courseOfStudies); 
// persist in database
return newStudent;
}

The key #result is a placeholder provided by Spring and refers to the return value of the method. The ID of the student is, therefore, the cache key. The cache entry is the return value of the method, the student in our example.

The method now creates a student object and stores it in the studentCache at the end. The next time this object is requested, it can be retrieved directly from the cache.

Best Practices

🔸Proper Configuration: Careful consideration of cache configuration, including size limits, eviction policies, and expiration times, is crucial to ensure optimal performance.

🔸Monitoring and Management: Ehcache provides monitoring and management features that allow you to keep track of cache usage, performance metrics, and potential issues. Utilize these features to ensure the health of your caching system.

🔸Performance Optimization: Optimizing the performance of your cache involves tuning various parameters, such as adjusting cache size, choosing appropriate eviction policies, and minimizing cache contention in a multi-threaded environment.

Integration with Spring Framework

🔹Spring Caching Annotations: Spring Framework provides annotations like @Cacheable, @CachePut, and @CacheEvict that can be used with Ehcache to simplify caching in Spring applications.

🔹Ehcache with Spring Boot: Integrating Ehcache with Spring Boot is straightforward. Spring Boot provides auto-configuration for Ehcache, making setting up caching in your Spring Boot applications easy.

Related read: Spring Boot With Redis Cache Using Annotation

Common Issues and Troubleshooting

🔸Memory Leaks: Improperly managed caches can lead to memory leaks. Regularly monitor and analyze your application’s memory usage to identify and address potential issues.

🔸Inconsistent Cache State: In distributed environments, ensuring a consistent cache state across nodes can be challenging. Terracotta integration or other distributed caching solutions can help address this concern.

🔸Performance Bottlenecks: Identifying and addressing performance bottlenecks in your caching system requires a thorough understanding of your application’s usage patterns and careful tuning of cache configurations.

Case Studies

Explore real-world examples of organizations successfully implementing Ehcache to improve application performance, scalability, and reliability.

Future Developments

Stay informed about the latest developments in the Ehcache ecosystem, including new features, updates, and community contributions.

coma

Conclusion

Ehcache is a powerful caching library that can significantly enhance the performance and scalability of Java applications. Understanding its features, architecture, and best practices is essential for effectively integrating caching into your projects.

Whether you are building a small application or a large-scale enterprise system, Ehcache provides the tools and flexibility needed to optimize data access and improve overall user experience.

Check out my GitHub to learn more about Ehcache.

Keep Reading

Keep Reading

Struggling with EHR integration? Learn about next-gen solutions in our upcoming webinar on Mar 6, at 11 AM EST.

Register Now

Let's create something together!