How do I cache data in a plugin?

Confluence includes a caching API, atlassian-cache, which should be used instead of custom cache solutions. The provided API ensures:

  • proper expiry of cache data (default expiry: 1 hour)
  • enables monitoring of cache usage by administrators
  • functions correctly in a Confluence cluster.

The remainder of this document describes how to use the atlassian-cache APIs.

Example

Below is a short example of some code using the atlassian-cache APIs.

import org.apache.commons.lang3.StringUtils;
import com.atlassian.cache.Cache;
import com.atlassian.cache.CacheLoader;
import com.atlassian.cache.CacheManager;
import com.atlassian.cache.CacheSettingsBuilder;
import com.atlassian.util.concurrent.NotNull;
// some imports omitted for clarity
 
public class ListPagesMacro implements Macro 
{
    private final Cache<String, String> cache;
    private final PageManager pageManager;
 
    public ListPagesMacro(CacheManager cacheManager, PageManager pageManager) {
        this.pageManager = pageManager;
        cache = cacheManager.getCache(ListPagesMacro.class.getName() + ".cache", 
                new ListPagesCacheLoader(),
                new CacheSettingsBuilder().expireAfterAccess(30, TimeUnit.MINUTES).build());    
    }
    
    @Override
    public String execute(Map<String, String> parameters, String body, ConversionContext context)
            throws MacroExecutionException
    {
        String spaceKey = (String) parameters.get("spaceKey");
        if (StringUtils.isBlank(spaceKey))
            spaceKey = context.getSpaceKey();
        if (StringUtils.isBlank(spaceKey))
            throw new MacroExecutionException("A spaceKey is required.");


        // if the spaceKey is not present in the cache then the ListPagesCacheLoader will create the value as
        // implemented in the 'load' method and it will be populated into the cache automatically.
        return cache.get(spaceKey);
    }
    
    // The loader class used to populate a cache entry on cache miss.
    private class ListPagesCacheLoader implements CacheLoader<String, String> 
	{
        @Override
        public String load(@NotNull String spaceKey)
        {
            return renderPageList(spaceKey);
        }
    }
    
    String renderPageList(String spaceKey)
    {
		// implementation goes here
    }
	...
}

Instructions

To use the Atlassian Cache API, you first need to get a CacheManager injected into your component (macro, action, etc). You do this by adding a setter or constructor parameter to your component, depending on whether you are using setter-based or constructor-based dependency injection.

To retrieve a cache from the cache manager, use a cache key which is unique to your plugin. We recommend using the fully qualified name of the class which uses the cache, plus a name which describes the contents of the cache.

The returned Cache has an API very similar to Java's Map. You can call put(Object, Object) to store a value in the cache, and get(Object) to look up a previously stored value.

In a single instance of Confluence, you can store any objects in the cache. In a clustered instance, you can only store keys and values which implement Serializable.

Always depend on CacheManager instead of its super interface CacheFactory. CacheFactory exported by Confluence is an instance of TransactionalCacheFactory with often surprising performance characteristics.

Cache configuration

If you don't specify a cache configuration explicitly then it is determined by Confluence by default, with the ability for the Confluence administrator to change the settings at runtime. The default expiry is one hour and the cache will store up to 1000 items. The least-recently used items will be automatically expired or removed if space is needed for new items. However it is preferable to create a cache specifically configured to the plugin requirements.

You should always try and set an expiry policy on the caches you create in order to avoid consuming excessive amounts of memory. For most applications a timed base expiry is most appropriate. It is usually very difficult to determine an appropriate number of cache entries that suits clients at all scales.

Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport