Setup Spring EnableCaching for Memcached


1. Setup CacheConfiguration
2. Extend AbstractCacheManager
3. Implement Cache
4. Implement CachingConfigurer

1. Setup CacheConfiguration

package com.example.cache;

import java.io.IOException;
import java.net.URISyntaxException;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.ConnectionFactory;
import net.spy.memcached.ConnectionFactoryBuilder;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.PlainCallbackHandler;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CacheConfiguration {

    @Bean
    public MemcachedClient memcachedCloudConfiguration() {
        try {
            AuthDescriptor ad = new AuthDescriptor(new String[] { "PLAIN" },
                    new PlainCallbackHandler(System.getenv("MEMCACHEDCLOUD_USERNAME"), System.getenv("MEMCACHEDCLOUD_PASSWORD")));

            MemcachedClient mc = new MemcachedClient(
                    new ConnectionFactoryBuilder()
                            .setTranscoder(new CustomSerializingTranscoder())
                            .setProtocol(ConnectionFactoryBuilder.Protocol.BINARY)
                            .setAuthDescriptor(ad).build(),
                    AddrUtil.getAddresses(System.getenv("MEMCACHEDCLOUD_SERVERS")));

            return mc;
        } catch (IOException ex) {
            // the Memcached client could not be initialized.
        }
        return null;
    }
}

2. Extend AbstractCacheManager

package com.example.cache;

import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractCacheManager;
import org.springframework.util.Assert;

import java.util.Collection;

/**
 * Created by tmichels on 3/19/15.
 */
public class MemCacheManager extends AbstractCacheManager {
    private final Collection<MemCache> internalCaches;

    public MemCacheManager(final Collection<MemCache> internalCaches) {
        this.internalCaches = internalCaches;
    }

    @Override
    protected Collection<? extends Cache> loadCaches() {
        Assert.notNull(internalCaches, "A collection caches is required and cannot be empty");
        return internalCaches;
    }
}

3. Implement Cache

package com.example.cache;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.transcoders.SerializingTranscoder;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;

import java.io.IOException;
import java.net.URISyntaxException;

/**
 * Created by tmichels on 3/19/15.
 */
public class MemCache implements Cache {

    @Autowired
    MemcachedClient cache;

    private final String name = "";
    private static final Logger LOGGER = Logger.getLogger(MemCache.class);

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Object getNativeCache() {
        return cache;
    }

    @Override
    public ValueWrapper get(final Object key) {
        Object value = null;
        try {
            value = cache.get(key.toString());
        } catch (final Exception e) {
            LOGGER.warn(e);
        }
        if (value == null) {
            return null;
        }
        return new SimpleValueWrapper(value);
    }

    @Override
    public void put(final Object key, final Object value) {
        cache.set(key.toString(), 7 * 24 * 3600, value);
        Assert.assertNotNull(get(key)); //This fails on the viewCache
    }

    @Override
    public void evict(final Object key) {
        this.cache.delete(key.toString());
    }

    @Override
    public void clear() {
        cache.flush();
    }
 }

4. Implement CachingConfigurer

package com.example.cache;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.interceptor.DefaultKeyGenerator;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class SimpleCacheConfiguration implements CachingConfigurer {

    @Override
    @Bean
    public CacheManager cacheManager() {
        CacheManager cacheManager;
        try {
            cacheManager = new MemCacheManager(internalCaches());
            return cacheManager;
        } catch (final URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    @Bean
    public Collection<MemCache> internalCaches() throws URISyntaxException {
        final Collection<MemCache> caches = new ArrayList<MemCache>();
        caches.add(new MemCache());
        return caches;
    }

    @Override
    public KeyGenerator keyGenerator() {
        return new DefaultKeyGenerator();
    }

}

1 Comment

  1. Sonal says:

    Hi,
    Thank you very much for your blog. It is very helpful.
    I have only one query, will you please let me know after adding all these configuration files for spring Memcached. can we use spring cache annotations like @Cachable, @CachePut so on?
    One more thing I would like to ask regarding,

    In MemCache.java class you have mentioned name variable which is cache name, so how spring boot application will get this name dynamically. eg. @Cacheable(“any-name”)

    Will you please help me to understand this. Thank you very much in advance for your valuable time.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s