Total Pageviews

2016/06/03

[Spring Framework] Caching in Spring

Problem
If I have a table which is used for the purpose of configuration. For example, if I provide an email service, we must have some information which does not change frequently (ex. smtp, port). 

In this case, we hope email service can retrieve data from cache instead of accessing database, except it had been changed.

How-To
1. create a Cache config class to enable caching.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.xxx.ecp.commons.service.cache;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// http://www.baeldung.com/spring-cache-tutorial
/*
 * To enable caching, Spring makes good use of annotations, much like enabling any other
 * configuration level feature in the framework.
 * 
 * The caching feature can be declaratively enabled by simply adding the @EnableCaching annotation
 * to any of the configuration classes:
 */
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        String cacheNames[] = new String[] { "comConfig" };
        // Construct a static ConcurrentMapCacheManager, managing caches for the specified cache
        // names only.
        return new ConcurrentMapCacheManager(cacheNames);
    }

}


2.  Enable caching behavior for a method
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.xxx.ecp.commons.repository.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import com.cht.commons.persistence.query.SqlExecutor;
import com.google.common.base.Strings;
import com.yuantalife.ecp.commons.entity.ComConfig;
import com.yuantalife.ecp.commons.repository.custom.ComConfigRepositoryCustom;

/**
 * The Class ComConfigRepositoryImpl.
 */
@Component
public class ComConfigRepositoryImpl implements ComConfigRepositoryCustom {

    @Autowired
    private SqlExecutor sqlExecutor;

    /**
     * {@inheritDoc} <br>
     * The simplest way to enable caching behavior for a method is to demarcate it with @Cacheable
     * and parameterize it with the name of the cache where the results would be stored
     */
    @Override
    @Cacheable("comConfig")
    public List<ComConfig> findByServiceType(String serviceType) {
        String sql = "select * from com_config where service_type = :serviceType";

        Map<String, String> parameter = new HashMap<String, String>();
        parameter.put("serviceType", serviceType);

        return sqlExecutor.queryForList(sql, parameter, ComConfig.class);
    }


}


3. When update com_config table (including create, update, delete), evict cache content so that fresh values can be loaded into the cache again
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.xxx.ecp.manage.common.service;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import com.cht.commons.security.user.UserHolder;
import com.yuantalife.ecp.commons.entity.ComConfig;
import com.yuantalife.ecp.commons.entity.ComConfigPK;
import com.yuantalife.ecp.commons.exception.EcpException;
import com.yuantalife.ecp.commons.repository.ComConfigRepository;

@Slf4j
@Service
public class Com010wService {

    @Autowired
    ComConfigRepository comConfigRepository;

    @CacheEvict(value = "comConfig", allEntries = true)
    public void create(ComConfig comConfig) {
        ComConfigPK pk = new ComConfigPK();
        pk.setConfigKey(comConfig.getConfigKey());
        pk.setServiceType(comConfig.getServiceType());
        ComConfig existingEntity = comConfigRepository.findOne(pk);

        if (existingEntity == null) {
            comConfig.setUserId(UserHolder.getUser().getId());
            comConfig.setUpdateDate(new Timestamp(new Date().getTime()));
            comConfigRepository.create(comConfig);
        } else {
            throw new EcpException(com.yuantalife.ecp.manage.common.StatusCodes.COM010001W());
        }

    }

    public List<ComConfig> query(String serviceType) {
        return comConfigRepository.findOrderByUpdateDateDesc(serviceType);
    }

    @CacheEvict(value = "comConfig", allEntries = true)
    public void save(ComConfig comConfig) {
        comConfig.setUserId(UserHolder.getUser().getId());
        comConfig.setUpdateDate(new Timestamp(new Date().getTime()));
        comConfigRepository.save(comConfig);
    }

    @CacheEvict(value = "comConfig", allEntries = true)
    public void delete(ComConfig comConfig) {
        ComConfigPK pk = new ComConfigPK();
        pk.setConfigKey(comConfig.getConfigKey());
        pk.setServiceType(comConfig.getServiceType());
        comConfigRepository.delete(pk);
    }
}


Reference
[1] http://www.baeldung.com/spring-cache-tutorial

No comments: