Thinking of using a cache: Spring Cache VS Caffeine native API

A recent study found that the local cache, in the development of Spring technology stack, you can either use the comment form Spring Cache operation caches, native API can also be used various caching schemes. So whether Spring is the most appropriate option it official? Then this article will be announced by a case for you.

Spring Cache

Since version 3.1, the Spring Framework provides support for transparently adding caching to an existing Spring application. The caching abstraction allows consistent use of various caching solutions with minimal impact on the code.

Spring Cache and slf4j, jdbc Similarly, a cache abstraction layer provided by Spring Framwork, you can access a variety of caching solutions to use, by integrating Spring Cache, we only need to operate the cache by a set of notes on it . Currently supported are the Generic , JCache (JSR-107) , EhCache 2.x , Hazelcast , Infinispan , Couchbase , Redis , Caffeine , the Simple , includes almost mainstream local caching scheme.

The main principle is to inject Cache and CacheManager two bean to Spring Context, and then by automated assembly technology Spring Boot will automatically inject the appropriate Cache and CacheManager implement the project according to the profile.

Local caching scheme

Java technology stack mature local cache program has been a lot, there are large and ehcache, but also a rising star Google Guava Cache. The following is a comparison of the three local cache frequently used programs, quoted from the blog how elegant design and the use of caching?

project ehcache Guava Cache Caffeine
Read and write performance it is good Well, we need to do out of operation well
Out algorithm Support for multiple elimination algorithm, LRU, LFU, FIFO LRU, general W-TinyLFU, good
Functional richness Function is very rich Function is very rich, refresh and support phantom reference, etc. Similar functions and Guava Cache
Tool size Great, the latest version 1.4MB Guava tools is in a small portion, less Generally, the latest version 644KB
Whether persistence Yes no no
Whether to support a cluster Yes no no

Currently more recommended is Caffeine, out of more advanced algorithms, and the support of Spring Cache's (the new version of Spring Cache is no longer supported Guava Cache). Caffeine is also the use of the code below native API.

Case

Used Spring Cache people should find it possible to easily cache CRUD operations through a few notes, and replaced by other caching scheme does not require you to make changes to the code, you also do not need to write boilerplate code such as the following:

{
    // 缓存命中
    if(cache.getIfPresent(key) != null){
        // todo
    }else{
        // 缓存未命中,IO 获取数据,结果存入缓存
        Object value = repo.getFromDB(key);
        cache.put(key,value);
    }
}

That learned here, I had doubts, since the Spring annotation of the development of cache, and also in a large number of blog on Spring Cache to lead, it is also the need to use native API it? After all, after the Spring Data JPA appear, we do very little attention to the backend ORM framework, and no longer directly use the Hibernate.

When I realized the needs of a project, the problem seems to suddenly see the light.

In fact, demand is very simple, a map originally maintained in the local HashMap, due to frequent changes and late into the database. However, due to the large amount of data is not the time and do not configure the mapping table, the data remains unchanged, so now learning the cache, you want it added. So now we need to do is:

  1. The method of mapping a full table reading table aliasMap(). And cache data to Caffeine.
  2. When a page mapping records support CRUD operations, and modify the mapping table, update the cache.
@Cacheable(value = "default", key = "#root.methodName")
@Override
public Map<String, String> aliasMap() {
    return getMapFromDB();
}

Since Spring Cache annotation is typically added to the class or method, in other words, the cache is the method returns the object. Obviously, to trigger another update cache object by a method does not work. So does that mean Spring Cache can not achieve it? Carefully to see what the principle Spring Cache, but it is still feasible.

Cache Cache and will inject the Spring CacheManager to two bean Spring Context, and then by an automatic assembly techniques Spring Boot, according to the project profile, and automatic injector suitable Cache CacheManager achieved. To see CaffeineCacheManager source:

public class CaffeineCacheManager implements CacheManager {
    private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap(16);
    private boolean dynamic = true;
    private Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder();
    @Nullable
    private CacheLoader<Object, Object> cacheLoader;
    private boolean allowNullValues = true;
}

Obviously, such a cache exists cacheMap ConcurrentHashMap in that as long as we are able to manually get to this instance of the bean to operate it, then this requirement can be achieved, the code is as follows:

@Autowired
private CacheManager cacheManager;
@Cacheable(value = "default", key = "#root.methodName")
@Override
public Map<String, String> aliasMap() {
    return getMapFromDB();
}

private Map<String, String> getMapFromDB() {
    Map<String, String> map = new HashMap<>();
    List<PartAlias> list = repository.findAll();
    list.forEach(x -> map.put(x.getAlias(), x.getName()));
    return map;
}

@Override
public PartAlias saveOrUpdateWithCache(PartAlias obj) {
    PartAlias partAlias = repository.saveAndFlush(obj);
    Cache cache = cacheManager.getCache("default");
    cache.clear();
    cache.put("aliasMap", getMapFromDB());
    return partAlias;
}

After testing, the above code is feasible. Obviously, encountered some slightly more complex needs, relying solely on Spring Cache annotation is not enough, we need to operate their own cache object. If you use the native API is very simple, and can respond to different needs.

What's More

The above demand, Spring Cache yet still be able to handle, but if you want to automatically load data and refresh it? Now Spring Cache is not well supported.

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=1024
    cache-names: cache1,cache2

The above code is used to configure the cache, combined with CaffeineCacheManager above source code, we can know, Spring Cache configuration is global, that is to say for example the maximum number, expiration date and other parameters are set for the entire cache, not individual settings for a cache. And for data loading and refresh Caffeine is CacheLoaderalso CaffeineCacheManagerthe common bean, so it lost the meaning of existence, after all, each cache data load and refresh the way the same is not possible.

Therefore, in the face of complex scenes, the students still have to Uehara's API, Spring Cache it is beyond its capability. I also write a utility class that can be used globally cache.

@Component
public class CaffeineCacheManager {
    private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

    /**
     * 缓存创建
     *
     * @param cacheName
     * @param cache
     */
    public void createCache(String cacheName, Cache cache) {
        cacheMap.put(cacheName, cache);
    }

    /**
     * 缓存获取
     *
     * @param name
     * @return
     */
    public synchronized Cache getCache(String name) {
        Cache cache = this.cacheMap.get(name);
        if (cache == null) {
            throw new IllegalArgumentException("No this cache.");
        }
        return cache;
    }

    @Autowired
    private static CaffeineCacheManager manager;
    public static void main(String[] args) {
        manager.createCache("default", Caffeine.newBuilder()
                .maximumSize(1024)
                .build());
        Cache<String, Object> cache = manager.getCache("default");
        // TODO
    }
}

Of course, come to mention, since it is Spring's routines, developers will always leave a way out, if willing to toss, CacheManager can read the code, and then re-implement according to their own needs to manage its own cache instance.

to sum up

This is not an introductory Spring Cache and use Caffeine articles (there is a need to read references), but rather to explore Spring Cache and Caffeine native API usage scenarios. Clearly, Spring family bucket sometimes may not be the best solution (the ability to rewrite another matter)! So we hope to have more online blog can focus on the use of the framework itself, rather than waking various integrated into Spring xxx.

appendix

yaml Configuration

initialCapacity: # 初始的缓存空间大小
maximumSize: # 缓存的最大条数
maximumWeight: # 缓存的最大权重
expireAfterAccess: # 最后一次写入或访问后经过固定时间过期
expireAfterWrite: # 最后一次写入后经过固定时间过期
refreshAfterWrite: # 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
weakKeys: # 打开 key 的弱引用
weakValues:  # 打开 value 的弱引用
softValues: # 打开 value 的软引用
recordStats: # 开发统计功能

Principle articles

Rational use of cache

The main purpose of the cache is to reduce the pressure of the main master database, the service can be obtained directly from the data cache to improve the speed of response, so that the original limited resources can serve more users.

From an engineering point of view, the introduction of the cache is not blind, if the pressure in the master database is not the case, do not need to add cache. Add more data middleware obviously will increase the cost of maintenance, but also there are some in actual use, such as caching breakdown, avalanche cache and other issues.

basic concept

  • Hit rate. Returns the correct number of results / cache request number, the higher the hit rate, indicating that the higher cache usage.
  • The largest element. The cache can store a maximum number of elements, more than once, the operation will be cleared by the appropriate strategy.
  • Clear strategy: FIFO, LFU, LRU

Cache type

The memory cache may be divided into a local cache mode and distributed cache.

  • Local cache: the local cache generally refers to the internal cache application process cache. Java technology stack, for example, but their realization HashMap as a data cache, can also be used as ready-caching programs, such as ehcache, caffeine and so on.
  • Distributed caching: caching and application of environmental isolates, will be stored separately in their own server or cluster, and multiple applications can be directly shared cache. Common Redis caching solutions have MemCache and so on.

This section is designed to allow everyone to have a basic understanding of the cache, the cache is not a specific technology, but a common technical solution, how to choose the right caching solution integrated into their projects and how to solve the introduction of cache focus on some of the classic problems, not discussed herein after produced. Details about the selection and caching can refer to:

references

Guess you like

Origin www.cnblogs.com/Sinte-Beuve/p/12009885.html