Guava------------Cache使用方法

时间:2022-11-12 20:44:43

 

    简单从这几个方面描述一下如何使用Cache,对Cache的各种原理介绍此处不涉及.

    1.使用场景

    2.如何使用Cache

    3.创建方式

    4. 如何和Spring搭配使用

+------------------------------------------------------分割线-------------------------------------------------------+

  1. Cache的使用场景

       一般而言,对于那些频繁需要查询比对的热点数据,我们采用使用缓存,对于数据量较小的,几条,几十条数据,而且需要加缓存的接口较少,这时候我们会采用Cache,建议使用Google提供的guava Cache,它简单易用的同时,性能也好. 而且线程安全(原因看源码) .对于那些较大数据量的,或者需要加缓存的接口较多的项目,可以去考虑Redis,memcached等等

  2. 如何使用Cache

     和Map的使用方式差不多,也可以和Spring结合,使用@Cacheable注解使用.

 3. 创建方式

    1. Cache Callable

    2. LoadingCache

    方式一:

Guava------------Cache使用方法Guava------------Cache使用方法
  1 package info.sanaulla.cache;
  2 
  3 import com.google.common.cache.Cache;
  4 import com.google.common.cache.CacheBuilder;
  5 import org.junit.Test;
  6 
  7 import java.util.concurrent.Callable;
  8 import java.util.concurrent.ExecutionException;
  9 import java.util.concurrent.TimeUnit;
 10 
 11 /**
 12  * *********************************************************
 13  * <p/>
 14  * Author:     XiJun.Gong
 15  * Date:       2016-08-17 16:59
 16  * Version:    default 1.0.0
 17  * Class description:
 18  * <p/>
 19  * *********************************************************
 20  */
 21 public class CacheDemo {
 22     private static Cache<Object, Object> cache = CacheBuilder.newBuilder()
 23             .maximumSize(100).expireAfterWrite(24, TimeUnit.HOURS)
 24             .recordStats()
 25             .build();
 26 
 27     public static Object get(Object key) throws ExecutionException {
 28 
 29         Object var = cache.get(key, new Callable<Object>() {
 30             @Override
 31             public Object call() throws Exception {
 32                 System.out.println("如果没有值,就执行其他方式去获取值");
 33                 String var = "Google.com.sg";
 34                 return var;
 35             }
 36         });
 37         return var;
 38     }
 39 
 40     public static void put(Object key, Object value) {
 41         cache.put(key, value);
 42     }
 43 
 44     class Person {
 45         private String name;
 46         private Integer age;
 47 
 48         public Person() {
 49         }
 50 
 51         public Person(String name, Integer age) {
 52             this.name = name;
 53             this.age = age;
 54         }
 55 
 56         public String getName() {
 57             return name;
 58         }
 59 
 60         public void setName(String name) {
 61             this.name = name;
 62         }
 63 
 64         public Integer getAge() {
 65             return age;
 66         }
 67 
 68         public void setAge(Integer age) {
 69             this.age = age;
 70         }
 71 
 72         @Override
 73         public String toString() {
 74             return "Person{" +
 75                     "名字='" + name + '\'' +
 76                     ", 年纪=" + age +
 77                     '}';
 78         }
 79     }
 80 
 81     @Test
 82     public void CacheTest() throws ExecutionException {
 83 
 84         Person person = new Person();
 85         person.setAge(11);
 86         person.setName("tSun");
 87         System.out.println(CacheDemo.get("man"));
 88         CacheDemo.put("man", new Person("hopg", 123));
 89         System.out.println(CacheDemo.get("man"));
 90         System.out.println(CacheDemo.get("man"));
 91 
 92         System.out.println(CacheDemo.get("person").toString());
 93         CacheDemo.put("person", person);
 94         System.out.println(CacheDemo.get("person").toString());
 95         System.out.println(CacheDemo.get("person").toString());
 96 
 97         System.out.println(CacheDemo.get("woman"));
 98         CacheDemo.put("women", new Person("google", 666));
 99         System.out.println(CacheDemo.get("woman"));
100         System.out.println(CacheDemo.get("woman"));
101         System.out.println(CacheDemo.get("man"));
102     }
103 }
View Code

结果:

 1 如果没有值,就执行其他方式去获取值
 2 Google.com.sg
 3 Person{名字='hopg', 年纪=123}
 4 Person{名字='hopg', 年纪=123}
 5 如果没有值,就执行其他方式去获取值
 6 Google.com.sg
 7 Person{名字='tSun', 年纪=11}
 8 Person{名字='tSun', 年纪=11}
 9 如果没有值,就执行其他方式去获取值
10 Google.com.sg
11 Google.com.sg
12 Google.com.sg
13 Person{名字='hopg', 年纪=123}

 

 方式二:

Guava------------Cache使用方法Guava------------Cache使用方法
  1 package info.sanaulla.cache;
  2 
  3 import com.google.common.cache.CacheBuilder;
  4 import com.google.common.cache.CacheLoader;
  5 import com.google.common.cache.LoadingCache;
  6 import org.junit.Test;
  7 
  8 import java.util.concurrent.ExecutionException;
  9 import java.util.concurrent.TimeUnit;
 10 
 11 /**
 12  * *********************************************************
 13  * <p/>
 14  * Author:     XiJun.Gong
 15  * Date:       2016-08-17 15:00
 16  * Version:    default 1.0.0
 17  * Class description:
 18  * <p>Cache Demo</p>
 19  * <p/>
 20  * *********************************************************
 21  */
 22 public class CacheUtil {
 23 
 24 
 25     private static LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
 26             .maximumSize(2)
 27             .expireAfterAccess(24, TimeUnit.HOURS)
 28             .recordStats()
 29             .build(new CacheLoader<Object, Object>() {
 30 
 31                 @Override
 32                 public Object load(Object key) throws Exception {
 33                     return key;
 34                 }
 35             });
 36 
 37     public static Object get(Object key) throws ExecutionException {
 38         Object var = cache.get(key);
 39 
 40         if (var.equals(key)) {
 41 
 42             System.out.println("执行其他操作,查询该值");
 43             /**执行其他操作,获取值**/
 44             Object object = "Google.com.hk";
 45             put(key, object);
 46         } else {
 47             System.out.println("从Cache中取值....");
 48         }
 49         return cache.get(key);
 50     }
 51 
 52     public static void put(Object key, Object value) {
 53         cache.put(key, value);
 54     }
 55 
 56     class Person {
 57         private String name;
 58         private Integer age;
 59 
 60         public Person() {
 61         }
 62 
 63         public Person(String name, Integer age) {
 64             this.name = name;
 65             this.age = age;
 66         }
 67 
 68         public String getName() {
 69             return name;
 70         }
 71 
 72         public void setName(String name) {
 73             this.name = name;
 74         }
 75 
 76         public Integer getAge() {
 77             return age;
 78         }
 79 
 80         public void setAge(Integer age) {
 81             this.age = age;
 82         }
 83 
 84         @Override
 85         public String toString() {
 86             return "Person{" +
 87                     "名字='" + name + '\'' +
 88                     ", 年纪=" + age +
 89                     '}';
 90         }
 91     }
 92 
 93     @Test
 94     public void TestCache() throws ExecutionException {
 95 
 96         Person person = new Person();
 97         person.setAge(11);
 98         person.setName("tSun");
 99         System.out.println(CacheUtil.get("man"));
100         CacheUtil.put("man", new Person("hopg", 123));
101         System.out.println(CacheUtil.get("man"));
102         System.out.println(CacheUtil.get("man"));
103 
104         System.out.println(CacheUtil.get("person").toString());
105         CacheUtil.put("person", person);
106         System.out.println(CacheUtil.get("person").toString());
107         System.out.println(CacheUtil.get("person").toString());
108 
109         System.out.println(CacheUtil.get("woman"));
110         CacheUtil.put("women", new Person("google", 666));
111         System.out.println(CacheUtil.get("woman"));
112         System.out.println(CacheUtil.get("woman"));
113         System.out.println(CacheUtil.get("man"));
114     }
115 }
View Code

结果:

 

 1 执行其他操作,查询该值
 2 Google.com.hk
 3 从Cache中取值....
 4 Person{名字='hopg', 年纪=123}
 5 从Cache中取值....
 6 Person{名字='hopg', 年纪=123}
 7 执行其他操作,查询该值
 8 Google.com.hk
 9 从Cache中取值....
10 Person{名字='tSun', 年纪=11}
11 从Cache中取值....
12 Person{名字='tSun', 年纪=11}
13 执行其他操作,查询该值
14 Google.com.hk
15 从Cache中取值....
16 Google.com.hk
17 从Cache中取值....
18 Google.com.hk
19 执行其他操作,查询该值
20 Google.com.hk

4. 如何和Spring结合使用

   因为我们需要使用Spring的注解,所以需要重写Spring的一些接口,然后进行自定义.

    4.1 首先简单了解一下@Cacheable,@CachePut,@CacheEvit

      对于cache和数据操作进行一个功能对应,如下图.

      cache             sql

     Cacheable       --save/insert   

关于Cacheable的简单说明:

      @Cacheable注解,如果是类被注解,那么该类所有的方法下,如果在查询时,会先去查询缓存,没有的话,再去调用方法查询,

并且方法的返回值都会被缓存,如果是方法被注解,那么查询的时候,也会遵从先缓存,然后在方法,并且该方法的返回值都会被缓存.

            CachePut        --update/Insert

           CacheEvit        --remove/delete

 

     4.2 首先我们需要实现接口Spring的BeanAware接口,以及InitializingBean接口,并实现FactoryBean接口,还有实现Spring的

AbstractTransactionSupportingCacheManager抽象类

过程大致如下:

1. 实现Cache接口

Guava------------Cache使用方法Guava------------Cache使用方法
  1 import com.google.common.cache.CacheBuilder;
  2 import com.google.common.cache.CacheBuilderSpec;
  3 import org.springframework.cache.Cache;
  4 import org.springframework.cache.support.SimpleValueWrapper;
  5 
  6 import java.io.Serializable;
  7 import java.util.concurrent.TimeUnit;
  8 
  9 import static com.google.common.base.Preconditions.checkNotNull;
 10 
 11 /**
 12  * *********************************************************
 13  * <p/>
 14  * Author:     XiJun.Gong
 15  * Date:       2016-08-22 15:47
 16  * Version:    default 1.0.0
 17  * Class description:
 18  * <p/>
 19  * *********************************************************
 20  */
 21 public class GuavaCache implements Cache {
 22 
 23 
 24     private static final Object NULL_HOLDER = new NullHolder();
 25 
 26     private final String name;
 27 
 28     private final com.google.common.cache.Cache<Object, Object> store;
 29 
 30     private final boolean allowNullValues;
 31 
 32     /**
 33      * Create a new GuavaCache with the specified name.
 34      *
 35      * @param name the name of the cache
 36      */
 37     public GuavaCache(String name) {
 38         this(name, CacheBuilder.newBuilder(), true);
 39     }
 40 
 41     /**
 42      * Create a new GuavaCache with the specified name.
 43      *
 44      * @param name            the name of the cache
 45      * @param allowNullValues whether to accept and convert null values for this cache
 46      */
 47     public GuavaCache(String name, boolean allowNullValues) {
 48         this(name, CacheBuilder.newBuilder(), allowNullValues);
 49     }
 50 
 51     /**
 52      * Create a new GuavaCache using the specified name and {@link com.google.common.cache.CacheBuilderSpec specification}
 53      *
 54      * @param name the name of the cache
 55      * @param spec the cache builder specification to use to build he cache
 56      */
 57     public GuavaCache(String name, CacheBuilderSpec spec, boolean allowNullValues) {
 58         this(name, CacheBuilder.from(spec), allowNullValues);
 59     }
 60 
 61     /**
 62      * Create a new GuavaCache using the specified name and {@link CacheBuilderSpec specification}
 63      *
 64      * @param name    the name of the cache
 65      * @param builder the cache builder to use to build the cache
 66      */
 67     public GuavaCache(String name, CacheBuilder<Object, Object> builder, boolean allowNullValues) {
 68         this.name = checkNotNull(name, "name is required");
 69         this.allowNullValues = allowNullValues;
 70         this.store = builder.maximumSize(CacheConstant.defaultCacheSize).
 71                 expireAfterWrite(CacheConstant.defaultCacheExpire, TimeUnit.MINUTES).
 72                 build();
 73     }
 74 
 75     @Override
 76     public String getName() {
 77         return this.name;
 78     }
 79 
 80     @Override
 81     public com.google.common.cache.Cache<Object, Object> getNativeCache() {
 82         return this.store;
 83     }
 84 
 85     @Override
 86     public ValueWrapper get(Object key) {
 87         Object value = this.store.getIfPresent(key);
 88         return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
 89     }
 90 
 91     @Override
 92     public void put(Object key, Object value) {
 93         this.store.put(key, value);
 94     }
 95 
 96     /**
 97      * remove the key of object
 98      *
 99      * @param key
100      */
101     @Override
102     public void evict(Object key) {
103         this.store.invalidate(key);
104     }
105 
106     /**
107      * clear all
108      */
109     @Override
110     public void clear() {
111         this.store.invalidateAll();
112     }
113 
114     /**
115      * Convert the given value from the internal store to a user value
116      * returned from the get method (adapting {@code null}).
117      *
118      * @param storeValue the store value
119      * @return the value to return to the user
120      */
121     protected Object fromStoreValue(Object storeValue) {
122         if (this.allowNullValues && storeValue == NULL_HOLDER) {
123             return null;
124         }
125         return storeValue;
126     }
127 
128     /**
129      * Convert the given user value, as passed into the put method,
130      * to a value in the internal store (adapting {@code null}).
131      *
132      * @param userValue the given user value
133      * @return the value to store
134      */
135     protected Object toStoreValue(Object userValue) {
136         if (this.allowNullValues && userValue == null) {
137             return NULL_HOLDER;
138         }
139         return userValue;
140     }
141 
142 
143     @SuppressWarnings("serial")
144     private static class NullHolder implements Serializable {
145 
146     }
147 }
View Code

 

2.实现Spring的FactoryBean,BeanAware,InitializingBean接口

Guava------------Cache使用方法Guava------------Cache使用方法
 1 import com.google.common.cache.CacheBuilder;
 2 import org.springframework.beans.factory.BeanNameAware;
 3 import org.springframework.beans.factory.FactoryBean;
 4 import org.springframework.beans.factory.InitializingBean;
 5 import org.springframework.util.StringUtils;
 6 
 7 /**
 8  * *********************************************************
 9  * <p/>
10  * Author:     XiJun.Gong
11  * Date:       2016-08-22 16:00
12  * Version:    default 1.0.0
13  * Class description:
14  * <p>{@link FactoryBean} for easy configuration of a {@link GuavaCache}.</p>
15  * <p/>
16  * *********************************************************
17  */
18 public class GuavaCacheFactoryBean
19         implements FactoryBean<GuavaCache>, BeanNameAware, InitializingBean {
20 
21     private String name = "";
22 
23     private boolean allowNullValues = true;
24 
25     private String spec;
26 
27     private GuavaCache cache;
28 
29     public void setName(String name) {
30         this.name = name;
31     }
32 
33     public void setAllowNullValues(boolean allowNullValues) {
34         this.allowNullValues = allowNullValues;
35     }
36 
37     public void setSpec(String spec) {
38         this.spec = spec;
39     }
40 
41     @Override
42     public void setBeanName(String name) {
43         if (!StringUtils.hasLength(this.name)) {
44             this.name = name;
45         }
46     }
47 
48     @Override
49     public void afterPropertiesSet() throws Exception {
50         if (StringUtils.hasText(this.spec)) {
51             this.cache = new GuavaCache(this.name, CacheBuilder.from(spec), allowNullValues);
52         } else {
53             this.cache = new GuavaCache(this.name, allowNullValues);
54         }
55     }
56 
57     @Override
58     public GuavaCache getObject() throws Exception {
59         return this.cache;
60     }
61 
62     @Override
63     public Class<?> getObjectType() {
64         return GuavaCache.class;
65     }
66 
67     @Override
68     public boolean isSingleton() {
69         return true;
70     }
71 
72 }
View Code

 

3.实现Spring的Manager类

Guava------------Cache使用方法Guava------------Cache使用方法
 1 import com.google.common.cache.CacheBuilder;
 2 import com.google.common.cache.CacheLoader;
 3 import org.springframework.cache.Cache;
 4 import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
 5 import org.springframework.util.StringUtils;
 6 
 7 import java.util.Collection;
 8 import java.util.Collections;
 9 import java.util.concurrent.TimeUnit;
10 
11 /**
12  * *********************************************************
13  * <p/>
14  * Author:     XiJun.Gong
15  * Date:       2016-08-22 16:09
16  * Version:    default 1.0.0
17  * Class description:
18  * <p> {@link org.springframework.cache.CacheManager} implementation backed by {@link GuavaCache}.</p>
19  * <p/>
20  * *********************************************************
21  */
22 public class GuavaCacheManager extends AbstractTransactionSupportingCacheManager {
23     private Collection<GuavaCache> caches;
24 
25     private String spec;
26 
27     private volatile CacheBuilder<Object, Object> cacheBuilder;
28 
29     private boolean allowNullValues = true;
30 
31     public GuavaCacheManager() {
32     }
33 
34     public void setCaches(Collection<GuavaCache> caches) {
35         this.caches = caches;
36     }
37 
38     public void setSpec(String spec) {
39         this.spec = spec;
40     }
41 
42     public String getSpec() {
43         return spec;
44     }
45 
46     public void setAllowNullValues(boolean allowNullValues) {
47         this.allowNullValues = allowNullValues;
48     }
49 
50     public boolean isAllowNullValues() {
51         return allowNullValues;
52     }
53 
54     @Override
55     protected Collection<? extends Cache> loadCaches() {
56         return (caches != null) ? caches : Collections.<GuavaCache>emptyList();
57     }
58 
59     @Override
60     public Cache getCache(String name) {
61         Cache cache = super.getCache(name);
62         if (cache == null) {
63             // create a new cache
64             cache = createGuavaCache(name);
65 
66             // add to collection of available caches
67             addCache(cache);
68         }
69         return cache;
70     }
71 
72     private GuavaCache createGuavaCache(String name) {
73         // create GuavaCache
74         return new GuavaCache(name, getCacheBuilder(), allowNullValues);
75     }
76 
77     private CacheBuilder<Object, Object> getCacheBuilder() {
78         if (cacheBuilder == null) {
79             synchronized (this) {
80                 if (cacheBuilder == null) {
81                     if (StringUtils.hasText(spec)) {
82                         cacheBuilder = CacheBuilder.from(spec);
83                     } else {
84                         cacheBuilder =CacheBuilder.newBuilder();
85                     }
86 
87                 }
88                 notify();
89             }
90         }
91 
92         return cacheBuilder;
93     }
94 
95 }
View Code

 

    4.3 配置spring配置文件applicationContext.xml

     

 1     <!--添加Cache-->
 2     <!--添加一个注解驱动不要掉-->
 3     <tx:annotation-driven/>
 4     <!--使用spring注解去扫描需要加缓存地方的的包-->
 5     <context:component-scan base-package="com.qunar.data.allinone.bus.testModel">
 6         <context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration"/>
 7     </context:component-scan>
 8     <!-- cache Manager-->
 9     <bean id="cacheManager" class="com.qunar.data.allinone.bus.cache.GuavaCacheManager">
10         <property name="caches">
11             <list>
12                 <bean class="com.qunar.data.allinone.bus.cache.GuavaCacheFactoryBean" name="msg-cache"/>
13             </list>
14         </property>
15     </bean>
16     <!--cache的注解驱动包-->
17     <cache:annotation-driven/>

测试即可

 1 import org.springframework.cache.annotation.Cacheable;
 2 import org.springframework.stereotype.Component;
 3 import org.springframework.stereotype.Service;
 4 
 5 /**
 6  * *********************************************************
 7  * <p/>
 8  * Author:     XiJun.Gong
 9  * Date:       2016-08-22 19:50
10  * Version:    default 1.0.0
11  * Class description:
12  * <p/>
13  * *********************************************************
14  */
15 @Component
16 public class TestName {
17 
18     @Cacheable(value = "msg-cache")
19     public String getName(String con) {
20         System.out.println("缓存中没有找到信息");
21         return con;
22     }
23 }
 1 import com.qunar.data.allinone.bus.testModel.TestName;
 2 import org.junit.Test;
 3 import org.junit.runner.RunWith;
 4 import org.springframework.test.context.ContextConfiguration;
 5 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 6 
 7 import javax.annotation.Resource;
 8 
 9 /**
10  * *********************************************************
11  * <p/>
12  * Author:     XiJun.Gong
13  * Date:       2016-08-22 19:30
14  * Version:    default 1.0.0
15  * Class description:
16  * <p/>
17  * *********************************************************
18  */
19 @RunWith(SpringJUnit4ClassRunner.class)
20 @ContextConfiguration(value = "classpath:applicationContext.xml")
21 public class CacheTest {
22 
23 
24     @Resource
25
26     TestName testName;
27 
28     @Test
29     public void testName() {
30         String username = "xijun.gong";
31         for (int i = 0; i < 10; i++) {
32             System.out.println("++++++++++++++++打印结果:   " + testName.getName(username));
33         }
34     }
35 }
缓存中没有找到信息
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二
++++++++++++++++打印结果:   王小二

 

 5. 扩展 

     在github上看到一篇关于,对于overflow时候,将数据写入到文件系统的例子,还不错,如果有这方面的需求可以看看.

地址:https://github.com/raphw/guava-cache-overflow-extension