Guava Cache本地缓存(LoadingCache)

在开发应用中,避免不了会使用到缓存,分布式缓存一般会用到redis、Memcache等常用,本地缓存像ehcache这种用的也是很多 

今天介绍下google guava框架插件提供的LoadingCache本地缓存,LoadingCache和ConcurrentMap差不多,都是线程安全的,只不过比ConcurrentMap多了一些其他的功能,如过期策略等

优点

1、线程安全的缓存,与ConcurrentMap相似,但前者增加了更多的元素失效策略,后者只能显示的移除元素。
2、提供了三种基本的缓存回收方式:基于容量回收、定时回收和基于引用回收。定时回收有两种:按照写入时间,最早写入的最先回收;按照访问时间,最早访问的最早回收。
3、监控缓存加载/命中情况。
4、集成了多部操作,调用get方式,可以在未命中缓存的时候,从其他地方获取数据源(DB,redis),并加载到缓存中

 

随手简单写的一个类(有待改进)

package com.shentb.hmb.cache;

import com.google.common.cache.*;
import com.shentb.hmb.service.impl.LoginService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public final class LoadingLocalCache {

    private static LoginService loginService;

    private static Logger logger = LoggerFactory.getLogger(LoadingLocalCache.class);

    private static LoadingCache loadingCache;

    private static LoadingLocalCache loadingLocalCache;

    private static int DEFAULT_CONCURRENCY_LEVEL= 4;

    private static int DEFAULT_EXPIRE= 1800;

    private static int DEFAULT_INITIAL_CAPACITY= 16;

    private static int DEFAULT_MAXIMUM_SIZE= 100;

    private static TimeUnit DEFAULT_TIME_UNIT= TimeUnit.SECONDS;

    @Autowired
    public void setLoginService(LoginService loginService) {
        LoadingLocalCache.loginService = loginService;
    }

    static {
        init();
    }

    private LoadingLocalCache(){}

    protected static void init() {
        loadingCache= CacheBuilder
                .newBuilder()
                //并发级别(同时写入缓存的线程数)
                .concurrencyLevel(DEFAULT_CONCURRENCY_LEVEL)
                //过期时间
                .expireAfterWrite(DEFAULT_EXPIRE,DEFAULT_TIME_UNIT)
                //初始容量
                .initialCapacity(DEFAULT_INITIAL_CAPACITY)
                //最大容量,超过之后默认按照LRU算法最近使用最少移除缓存项    
                .maximumSize(DEFAULT_MAXIMUM_SIZE)
                //设置统计缓存的命中率
                .recordStats()
                .removalListener(new RemovalListener() {
                    @Override
                    public void onRemoval(RemovalNotification notification) {
                        logger.info(notification.getKey() + " was removed, cause is " + notification.getCause());
                    }
                })
                //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
                .build(
                        new CacheLoader() {
                            @Override
                            public Object load(String key) throws Exception {
                                return loginService.selectByPhoneNo(key);
                            }
                        }
                );
    }

    public static Object put(String key, Object value){
        loadingCache.put(key, value);
        return value;
    }

    public static Object get(String key) throws Exception {
        return loadingCache.get(key);
    }

    public static  T checkNotNull(T reference) {
        if (reference == null) {
            throw new NullPointerException();
        }
        return reference;
    }


//        System.out.println(sellerContactVOCache.stats().toString());
}

常用方法:

get(K):这个方法要么返回已经缓存的值,要么使用CacheLoader向缓存原子地loading新值(就是上面说的当缓存没有值的时候执行Load方法)

put(key, value):这个方法可以直接显示地向缓存中插入值,这会直接覆盖掉已有键之前映射的值。

缓存回收:

CacheBuilder.maximumSize(long):这个方法规定缓存项的数目不超过固定值(其实你可以理解为一个Map的最大容量),尝试回收最近没有使用或总体上很少使用的缓存项

定时回收(Timed Eviction):

expireAfterAccess(long, TimeUnit):缓存项在给定时间内没有被读/写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。

expireAfterWrite(long, TimeUnit):缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变得陈旧不可用,这种回收方式是可取的。

显式清除:

任何时候,你都可以显式地清除缓存项,而不是等到它被回收:

个别清除:Cache.invalidate(key)   批量清除:Cache.invalidateAll(keys)   清除所有缓存项:Cache.invalidateAll()

移除监听器

通过CacheBuilder.removalListener(RemovalListener),可以声明一个监听器,以便缓存项被移除时做一些额外操作。缓存项被移除时,RemovalListener会获取移除通知[RemovalNotification],其中包含移除原因[RemovalCause]、键和值

你可能感兴趣的:(java,个人总结)