Configuring Ehcache

In order to start using Ehcache, you will need to configure your first CacheManager and Cache. This can be achieved through programmatic configuration or XML.

If you are looking to use the JSR-107, aka javax.cache API, you should start by reading the Ehcache 3.x JSR-107 Provider page.

Programmatic configuration

Java configuration is most easily achieved through the use of builders that offer a fluent API.

As with the previous versions of Ehcache, the canonical way of dealing with Cache is through a CacheManager.

CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder() (1)
    .withCache("preConfigured",
        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))) (2)
    .build(); (3)
cacheManager.init(); (4)

Cache<Long, String> preConfigured =
    cacheManager.getCache("preConfigured", Long.class, String.class); (5)

Cache<Long, String> myCache = cacheManager.createCache("myCache", (6)
    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));

myCache.put(1L, "da one!"); (7)
String value = myCache.get(1L); (8)

cacheManager.removeCache("preConfigured"); (9)

cacheManager.close(); (10)
1 The static method org.ehcache.config.builders.CacheManagerBuilder.newCacheManagerBuilder returns a new org.ehcache.config.builders.CacheManagerBuilder instance.
2 Use the builder to define a Cache with alias "preConfigured". This cache will be created when cacheManager.build() is invoked on the actual CacheManager instance. The first String argument is the cache alias, which is used to retrieve the cache from the CacheManager. The second argument, org.ehcache.config.CacheConfiguration, is used to configure the Cache. We use the static newCacheConfigurationBuilder() method on org.ehcache.config.builders.CacheConfigurationBuilder to create a default configuration.
3 Finally, invoking build() returns a fully instantiated, but uninitialized, CacheManager we can use.
4 Before using the CacheManager it needs to be initialized, which can be done in 1 of 2 ways: Calling CacheManager.init() on the CacheManager instance, or calling the CacheManagerBuilder.build(boolean init) method with the boolean parameter set to true.
5 A cache is retrieved by passing its alias, key type and value type to the CacheManager. For instance, to obtain the cache declared in step 2 you need its alias="preConfigured", keyType=Long.class and valueType=String.class. For type-safety, we ask for both key and value types to be passed in. If these differ from the ones we expect, the CacheManager throws a ClassCastException early in the application’s lifecycle. This guards the Cache from being polluted by random types.
6 The CacheManager can be used to create new Cache instances as needed. Just as in step 2, it requires passing in an alias as well as a CacheConfiguration. The instantiated and fully initialized Cache added will be returned and/or accessed through the CacheManager.getCache API.
7 The newly added Cache can now be used to store entries, which are comprised of key value pairs. The put method’s first parameter is the key and the second parameter is the value. Remember the key and value types must be the same types as those defined in the CacheConfiguration. Additionally the key must be unique and is only associated with one value.
8 A value is retrieved from a cache by calling the cache.get(key) method. It only takes one parameter which is the key, and returns the value associated with that key. If there is no value associated with that key then null is returned.
9 We can CacheManager.removeCache(String) a given Cache. The CacheManager will not only remove its reference to the Cache, but will also close it. The Cache releases all locally held transient resources (such as memory). References to this Cache become unusable.
10 In order to release all transient resources (memory, threads, …​) a CacheManager provides to Cache instances it manages, you have to invoke CacheManager.close(), which in turns closes all Cache instances known at the time.

Here is a shorter version featuring 3 important things:

try(CacheManager cacheManager = newCacheManagerBuilder() (1)
  .withCache("preConfigured", newCacheConfigurationBuilder(Long.class, String.class, heap(10))) (2)
  .build(true)) { (3)

  // Same code as before [...]
}
1 A CacheManager implements Closeable so can be closed automatically by a try-with-resources. A CacheManager must be closed cleanly. In a finally block, with a try-with-resources or (more frequent for normal applications) in some shutdown hook.
2 Builders having different names, you can use static imports for all of them.
3 The CacheManager is initialized using build(true).

XML configuration

You can create an XML file to configure a CacheManager.

<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"> (1)
    <key-type>java.lang.String</key-type> (2)
    <value-type>java.lang.String</value-type> (2)
    <resources>
      <heap unit="entries">20</heap> (3)
      <offheap unit="MB">10</offheap> (4)
    </resources>
  </cache>

  <cache-template name="myDefaults"> (5)
    <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"> (6)
    <key-type>java.lang.Number</key-type>
  </cache>

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

</config>
1 Declares a Cache aliased to foo.
2 The keys and values of foo are declared as type String; if not specified, the default is java.lang.Object.
3 foo is declared to hold up to 2,000 entries on heap…​
4 …​as well as up to 500 MB of off-heap memory before it starts evicting
5 <cache-template> elements let you create an abstract configuration that further <cache> configurations can then "extend"
6 bar is such a Cache. bar uses the <cache-template> named myDefaults and overrides its key-type to a wider type.
7 simpleCache is another such Cache. It uses myDefaults configuration for its sole CacheConfiguration.

Refer to the XML documentation for more details on the XML format.

In order to parse an XML configuration, you can use the XmlConfiguration type:

URL myUrl = getClass().getResource("/my-config.xml"); (1)
Configuration xmlConfig = new XmlConfiguration(myUrl); (2)
CacheManager myCacheManager = CacheManagerBuilder.newCacheManager(xmlConfig); (3)
1 Obtain a URL to your XML file location
2 Instantiate an XmlConfiguration passing the XML file URL to it
3 Using the static org.ehcache.config.builders.CacheManagerBuilder.newCacheManager(org.ehcache.config.Configuration) lets you create your CacheManager instance using the Configuration from the XmlConfiguration

Creating a cache manager with clustering support

To enable Clustering with Terracotta, firstly you will have to start the Terracotta server configured with clustered storage. In addition, for creating the cache manager with clustering support, you will need to provide the clustering service configuration:

CacheManagerBuilder<PersistentCacheManager> clusteredCacheManagerBuilder =
    CacheManagerBuilder.newCacheManagerBuilder() (1)
        .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application")) (2)
            .autoCreate()); (3)
PersistentCacheManager cacheManager = clusteredCacheManagerBuilder.build(true); (4)

cacheManager.close(); (5)
1 Returns the org.ehcache.config.builders.CacheManagerBuilder instance;
2 Use the ClusteringServiceConfigurationBuilder's static method .cluster(URI) for connecting the cache manager to the clustering storage at the URI specified that returns the clustering service configuration builder instance. The sample URI provided in the example points to the clustered storage with clustered storage identifier my-application on the Terracotta server (assuming the server is running on localhost and port 9410); the query-param auto-create creates the clustered storage in the server if it doesn’t already exist.
3 Returns a fully initialized cache manager that can be used to create clustered caches.
4 Auto-create the clustered storage if it doesn’t already exist.
5 Close the cache manager.
See the clustered cache documentation for more information on this feature.

Storage Tiers

Ehcache 3, as in previous versions, offers a tiering model to allow storing increasing amounts of data on slower tiers (which are generally more abundant).

The idea is that resources related to faster storage are more rare, but are located where the 'hottest' data is preferred to be. Thus less-hot (less frequently used) data is moved to the more abundant but slower tiers. Hotter data is moved onto the faster tiers.

Three tiers

A classical example would be using 3 tiers with a persistent disk storage.

PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
    .with(CacheManagerBuilder.persistence(new File(getStoragePath(), "myData"))) (1)
    .withCache("threeTieredCache",
        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
            ResourcePoolsBuilder.newResourcePoolsBuilder()
                .heap(10, EntryUnit.ENTRIES) (2)
                .offheap(1, MemoryUnit.MB) (3)
                .disk(20, MemoryUnit.MB, true) (4)
            )
    ).build(true);

Cache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class, String.class);
threeTieredCache.put(1L, "stillAvailableAfterRestart"); (5)

persistentCacheManager.close();
1 If you wish to use disk storage (like for persistent Cache instances), you’ll have to provide a location where data should be stored on disk to the CacheManagerBuilder.persistence() static method.
2 You define a resource pool for the heap. This will be your faster but smaller pool.
3 You define a resource pool for the off-heap. Still pretty fast and a bit bigger.
4 You define a persistent resource pool for the disk. It is persistent because said it should be (last parameter is true).
5 All values stored in the cache will be available after a JVM restart (assuming the CacheManager has been closed cleanly by calling close()).

For details, read the tiering documentation.

Data freshness

In Ehcache, data freshness is controlled through Expiry. The following illustrates how to configure a time-to-live expiry.

CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
        ResourcePoolsBuilder.heap(100)) (1)
    .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(20))) (2)
    .build();
1 Expiry is configured at the cache level, so start by defining a cache configuration,
2 then add to it an Expiry, here using the predefined time-to-live one, configured with the required Duration.

See the section on expiry for more information about the options available.

Advanced topics

A number of advanced topics that were discussed here have been moved out, see below.

User managed cache

See the user managed cache documentation for more information on this feature.

Byte-sized heap

See the relevant section in the tiering documentation for more information on this feature.

Update ResourcePools

See the relevant section in the tiering documentation for more information on this feature.

Off-heap

See the tiering documentation for more information on this feature.

Disk persistence

See the tiering documentation for more information on this feature.