1.Guava------------Cache使用方法

来源:互联网 发布:药品数据查询 编辑:程序博客网 时间:2024/06/10 08:27


http://www.cnblogs.com/gongxijun/p/5781108.html

 简单从这几个方面描述一下如何使用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

    方式一:

复制代码
  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 }
复制代码

结果:

复制代码
 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.sg11 Google.com.sg12 Google.com.sg13 Person{名字='hopg', 年纪=123}
复制代码

 

 方式二:

复制代码
  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 }
复制代码

结果:

 

复制代码
 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.hk15 从Cache中取值....16 Google.com.hk17 从Cache中取值....18 Google.com.hk19 执行其他操作,查询该值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接口

复制代码
  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 key100      */101     @Override102     public void evict(Object key) {103         this.store.invalidate(key);104     }105 106     /**107      * clear all108      */109     @Override110     public void clear() {111         this.store.invalidateAll();112     }113 114     /**115      * Convert the given value from the internal store to a user value116      * returned from the get method (adapting {@code null}).117      *118      * @param storeValue the store value119      * @return the value to return to the user120      */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 value133      * @return the value to store134      */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 }
复制代码

 

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

复制代码
 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.Gong11  * Date:       2016-08-22 16:0012  * Version:    default 1.0.013  * Class description:14  * <p>{@link FactoryBean} for easy configuration of a {@link GuavaCache}.</p>15  * <p/>16  * *********************************************************17  */18 public class GuavaCacheFactoryBean19         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     @Override42     public void setBeanName(String name) {43         if (!StringUtils.hasLength(this.name)) {44             this.name = name;45         }46     }47 48     @Override49     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     @Override58     public GuavaCache getObject() throws Exception {59         return this.cache;60     }61 62     @Override63     public Class<?> getObjectType() {64         return GuavaCache.class;65     }66 67     @Override68     public boolean isSingleton() {69         return true;70     }71 72 }
复制代码

 

3.实现Spring的Manager类

复制代码
 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.Gong15  * Date:       2016-08-22 16:0916  * Version:    default 1.0.017  * 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     @Override55     protected Collection<? extends Cache> loadCaches() {56         return (caches != null) ? caches : Collections.<GuavaCache>emptyList();57     }58 59     @Override60     public Cache getCache(String name) {61         Cache cache = super.getCache(name);62         if (cache == null) {63             // create a new cache64             cache = createGuavaCache(name);65 66             // add to collection of available caches67             addCache(cache);68         }69         return cache;70     }71 72     private GuavaCache createGuavaCache(String name) {73         // create GuavaCache74         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 }
复制代码

 

    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:5010  * Version:    default 1.0.011  * Class description:12  * <p/>13  * *********************************************************14  */15 @Component16 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.Gong13  * Date:       2016-08-22 19:3014  * Version:    default 1.0.015  * Class description:16  * <p/>17  * *********************************************************18  */19 @RunWith(SpringJUnit4ClassRunner.class)20 @ContextConfiguration(value = "classpath:applicationContext.xml")21 public class CacheTest {22 23 24     @Resource2526     TestName testName;27 28     @Test29     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

  

 




http://www.cnblogs.com/gongxijun/p/5781108.html



0 0