美文网首页
Spring Cache(2)

Spring Cache(2)

作者: 不知名的蛋挞 | 来源:发表于2018-11-11 22:49 被阅读0次

直到现在,我们已经学会了如何使用开箱即用的 spring cache,这基本能够满足一般应用对缓存的需求。

但现实总是很复杂,当你的用户量上去或者性能跟不上,总需要进行扩展,这个时候你或许对其提供的内存缓存不满意了,因为其不支持高可用性,也不具备持久化数据能力,这个时候,你就需要自定义你的缓存方案了。还好,spring 也想到了这一点。我们先不考虑如何持久化缓存,毕竟这种第三方的实现方案很多。我们要考虑的是,怎么利用 spring 提供的扩展点实现我们自己的缓存,且在不改原来已有代码的情况下进行扩展。

首先,我们需要提供一个 CacheManager接口的实现,这个接口告诉 spring 有哪些 cache 实例,spring 会根据 cache 的名字查找 cache 的实例。另外还需要自己实现 Cache接口,Cache 接口负责实际的缓存逻辑,例如增加键值对、存储、查询和清空等。

利用 Cache 接口,我们可以对接任何第三方的缓存系统,例如 EHCache、OSCache,甚至一些内存数据库例如 memcache 或者 redis 等。下面我举一个简单的例子说明如何做。

public class MyCacheManager extends AbstractCacheManager { 
   private Collection<? extends MyCache> caches; 
  
   /** 
   * Specify the collection of Cache instances to use for this CacheManager. 
   */ 
   public void setCaches(Collection<? extends MyCache> caches) { 
     this.caches = caches; 
   } 

   @Override 
   protected Collection<? extends MyCache> loadCaches() { 
     return this.caches; 
   } 
 }

上面的自定义的 CacheManager 实际继承了 spring 内置的 AbstractCacheManager,实际上仅仅管理 MyCache 类的实例。

下面是MyCache的定义:

 public class MyCache implements Cache { 
   private String name; 
   private Map<String,Account> store = new HashMap<String,Account>();; 
  
   public MyCache() { 
   } 
  
   public MyCache(String name) { 
     this.name = name; 
   } 
  
   @Override 
   public String getName() { 
     return name; 
   } 
  
   public void setName(String name) { 
     this.name = name; 
   } 

   @Override 
   public Object getNativeCache() { 
     return store; 
   } 

   @Override 
   public ValueWrapper get(Object key) { 
     ValueWrapper result = null; 
     Account thevalue = store.get(key); 
     if(thevalue!=null) { 
       thevalue.setPassword("from mycache:"+name); 
       result = new SimpleValueWrapper(thevalue); 
     } 
     return result; 
   } 

   @Override 
   public void put(Object key, Object value) { 
     Account thevalue = (Account)value; 
     store.put((String)key, thevalue); 
   } 

   @Override 
   public void evict(Object key) { 
   } 

   @Override 
   public void clear() { 
   } 
 }

上面的自定义缓存只实现了很简单的逻辑,但这是我们自己做的,也很令人激动是不是,主要看 get 和 put 方法,其中的 get 方法留了一个后门,即所有的从缓存查询返回的对象都将其 password 字段设置为一个特殊的值,这样我们等下就能演示“我们的缓存确实在起作用!”了。

这还不够,spring 还不知道我们写了这些东西,需要通过 spring*.xml 配置文件告诉它:

<cache:annotation-driven /> 

 <bean id="cacheManager" class="com.rollenholt.spring.cache.MyCacheManager">
     <property name="caches"> 
       <set> 
       <!-- 
           p:name属性大概等同于<property name="name" ref="Cache中的name"></property>是给
           Cache类中的name属性注入名字
        -->
         <bean class="com.rollenholt.spring.cache.MyCache" p:name="accountCache" /> 
       </set> 
     </property> 
</bean> 

接下来我们来编写测试代码:

Account account = accountService.getAccountByName("someone"); 
logger.info("passwd={}", account.getPassword()); 
account = accountService.getAccountByName("someone"); 
logger.info("passwd={}", account.getPassword()); 

上面的测试代码主要是先调用 getAccountByName 进行一次查询,这会调用数据库查询,然后缓存到 mycache 中,然后我打印密码,应该是空的;下面我再次查询 someone 的账号,这个时候会从 mycache 中返回缓存的实例,记得上面的后门么?我们修改了密码,所以这个时候打印的密码应该是一个特殊的值。

相关文章

网友评论

      本文标题:Spring Cache(2)

      本文链接:https://www.haomeiwen.com/subject/jqiffqtx.html