spring-cache-1

原创 2017年11月15日 15:39:35
Spring的缓存技术:
源码分析:
interface ConcurrentMap<K, V> extends Map<K, V>  <--实现-- class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, Serializable  //并发map集合

用户所存储缓存的数据池: class ConcurrentMapCache extends AbstractValueAdaptingCache
    private final ConcurrentMap<Object, Object> store; //实际存储对象
    T get(Object key, Callable<T> valueLoader)         //获取指定key的缓存
    void put(Object key, Object value)                 //存储一个缓存

abstract class AbstractValueAdaptingCache implements Cache  //所属缓存类型

Spring框架运行时需要的抽象的缓存技术的声明: interface Cache{
    String getName();                       //缓存的名字
    Object getNativeCache();                //得到底层使用的缓存,如Ehcache
    ValueWrapper get(Object key);           //根据key得到一个ValueWrapper,然后调用其get方法获取值
    <T> T get(Object key, Class<T> type);   //根据key,和value的类型直接获取value
    void put(Object key, Object value);     //往缓存放数据
    void evict(Object key);                 //从缓存中移除key对应的缓存
    void clear();                           //清空缓存
    interface ValueWrapper {                //缓存值的Wrapper
        Object get();                       //得到真实的value
    }
}

Spring框架运行时需要的抽象的一组缓存技术的声明: interface CacheManager {
   Cache getCache(String name);            //单个缓存抽象声明
   Collection<String> getCacheNames();     //所有缓存技术的类型的名称
}

并发封装:          class ConcurrentMapCacheManager     implements CacheManager, BeanClassLoaderAware //解决并发导致的问题

重量级工厂并发封装: class ConcurrentMapCacheFactoryBean implements FactoryBean<ConcurrentMapCache>, BeanNameAware, InitializingBean //提供构建方法而无需每次都创建

组合封装:          class CompositeCacheManager          implements CacheManager, InitializingBean //用来组合多种类型的缓存并轮询从多种缓存源中获取数据

一次设置缓存的过程: ConcurrentMapCacheManager.getCache("缓存技术类型名称")(ConcurrentMapCache).get[ConcurrentMap](name);
一次设置取出的过程: ConcurrentMapCacheManager.getCache("缓存技术类型名称")(ConcurrentMapCache).put[ConcurrentMap](name,value);


开发者使用时:
@CachePut:应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存,根据返回值按照形参值进行添加/修改
比如说:save/update
@interface CachePut {
    String[] value();              //缓存的名字,可以把数据写到多个缓存,别名
    String key() default "";       //缓存key,如果不指定将使用默认的KeyGenerator生成,后边介绍
    String condition() default ""; //满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断
    String unless() default "";    //用于否决缓存更新的,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了
}
@CacheEvict:即应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据,按照形参值进行删除
@interface CacheEvict {
    String[] value();                        //缓存的名字,可以把数据写到多个缓存,别名
    String key() default "";                 //缓存key,如果不指定将使用默认的KeyGenerator生成,后边介绍
    String condition() default "";           //满足缓存条件的数据才会清理缓存,condition在调用方法之前和之后都会判断
    boolean allEntries() default false;      //是否移除所有数据
    boolean beforeInvocation() default false;//是调用方法之前移除/还是调用之后移除
比如说:delete/deleteAll
@Cacheable:应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中:
public @interface Cacheable {
    String[] value();             //缓存的名字,可以把数据写到多个缓存,别名
    String key() default "";      //缓存key,如果不指定将使用默认的KeyGenerator生成,后边介绍
    String condition() default "";//满足缓存条件的数据才会放入取出缓存,condition在调用方法之前和之后都会判断
    String unless() default "";   //用于否决缓存更新的,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了
比如说:get/search
运行流程:
    1、首先执行@CacheEvict(如果beforeInvocation=true且condition 通过),如果allEntries=true,则清空所有
    2、接着收集@Cacheable(如果condition 通过,且key对应的数据不在缓存),放入cachePutRequests(也就是说如果cachePutRequests为空,则数据在缓存中)
    3、如果cachePutRequests为空且没有@CachePut操作,那么将查找@Cacheable的缓存,否则result=缓存数据(也就是说只要当没有cache put请求时才会查找缓存)
    4、如果没有找到缓存,那么调用实际的API,把结果放入result
    5、如果有@CachePut操作(如果condition 通过),那么放入cachePutRequests
    6、执行cachePutRequests,将数据写入缓存(unless为空或者unless解析结果为false);
    7、执行@CacheEvict(如果beforeInvocation=false 且 condition 通过),如果allEntries=true,则清空所有
注意:
    在同一个业务方法上,如果有@CachePut操作,即使有@Cacheable也不会从缓存中读取;
    问题很明显,如果要混合多个注解使用,不能组合使用@CachePut和@Cacheable;
    官方说应该避免这样使用(解释是如果带条件的注解相互排除的场景);
Key生成器:
    如果在Cache注解上没有指定key的话@CachePut(value = "user"),spring默认会使用KeyGenerator进行生成一个key:
功能描述:interface KeyGenerator {
   Object generate(Object target, Method method, Object... params);
}
具体实现:class SimpleKeyGenerator implements KeyGenerator {
   @Override
   public Object generate(Object target, Method method, Object... params) {
      return generateKey(params);
   }
   public static Object generateKey(Object... params) {
      if (params.length == 0) { //如果参数的长度为0,使用的是同一个simpleKey
         return SimpleKey.EMPTY;
      }
      if (params.length == 1) { //如果参数的个数为1个
         Object param = params[0];
         if (param != null && !param.getClass().isArray()) {
            return param;
         }
      }
      return new SimpleKey(params);
   }
}
key: class SimpleKey implements Serializable{
    public static final SimpleKey EMPTY = new SimpleKey();
    private final Object[] params;
    private final int hashCode;
    SimpleKey(Object... elements) {
        this.params = new Object[elements.length];
        System.arraycopy(elements, 0, this.params, 0, elements.length);
        this.hashCode = Arrays.deepHashCode(this.params);
    }
}
另外:
    System下的static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length); 拷贝源数组中指定起始位置到结尾的数据到目标数组的开始位置到源数组的长度
SpEL上下文:
    | **名字**          | **位置** | **描述**                                   | **示例**                 |
    | --------------- | ------ | ---------------------------------------- | ---------------------- |
    | methodName      | root对象 | 当前被调用的方法名                                | `#root.methodName`     |
    | method          | root对象 | 当前被调用的方法                                 | `#root.method.name`    |
    | target          | root对象 | 当前被调用的目标对象                               | `#root.target`         |
    | targetClass     | root对象 | 当前被调用的目标对象类                              | `#root.targetClass`    |
    | args            | root对象 | 当前被调用的方法的参数列表                            | `#root.args[0]`        |
    | caches          | root对象 | 当前方法调用使用的缓存列表(如@Cacheable(value={"cache1", "cache2"})),则有两个cache | `#root.caches[0].name` |
    | *argument name* | 执行上下文  | 当前被调用的方法的参数,如findById(Long id),我们可以通过#id拿到参数 | #user.id               |
    | result          | 执行上下文  | 方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless’,'cache evict'的beforeInvocation=false) | `#result`              |
    ...
    通过#对象.属性名获取spEL值,用于condition中做条件判断
条件判断(condition):
    例如: @Cacheable(condition = "#id lt 10")
    常用:
        lt:小于,gt:大于,ne:值不等,eq:值相等
    当condition表达式的值为true时执行缓存相关操作
    当unless表达式的值为false是执行缓存相关操作
    常与beforeInvocation=false属性一起使用,为true表示在方法执行之前执行,为false表示在方法之前之后执行
组合注解: @Caching:
@Caching(put = {},evict = {},cacheable = {})
版权声明:本文为博主原创文章,未经博主允许不得转载。

Spring Boot缓存实战 Redis + Caffeine 实现多级缓存

在前文我们介绍了如何使用Redis或者Caffeine来做缓存。 Spring Boot缓存实战 Redis 设置有效时间和自动刷新缓存-2Spring Boot缓存实战 Caffeine 问题描...
  • xiaolyuh123
  • xiaolyuh123
  • 2017年12月21日 17:50
  • 405

Spring配置错误记录

更多Spring问题由于发生时未记录而遗忘了~~~~~~~ 现在动动手 解决方案由于不是源头分析因而仅供参考!!! 严重: Exception sending context destroyed...
  • ssd1daan
  • ssd1daan
  • 2015年08月13日 16:20
  • 4164

spring-cache-1

Spring的缓存技术: 源码分析: interface ConcurrentMap extends Map extends AbstractMap implements ConcurrentMa...
  • qq_35559756
  • qq_35559756
  • 2017年11月15日 15:39
  • 104

sping注解cache

Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使用的抽...
  • u011563331
  • u011563331
  • 2016年08月18日 16:01
  • 599

Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

转自:http://tom-seed.iteye.com/blog/2104430 缓存注解有以下三个: @Cacheable      @CacheEvict     @CachePut...
  • wjacketcn
  • wjacketcn
  • 2016年03月21日 13:49
  • 16139

解决升级到Android Studio 3 Beta版本编译异常

Gradle sync failed: Cause: java.lang.NullPointerException 问题引入部分项目从alpha版本导入到beta版本的时候会触发以上异常,无论是reb...
  • qiujuer
  • qiujuer
  • 2017年08月17日 10:57
  • 1104

Supporting Different Screen Sizes

Use Layout Aliases The smallest-width qualifier is available only on Android 3.2 and above. Theref...
  • jiabailong
  • jiabailong
  • 2015年10月30日 10:12
  • 358

Spring使用Cache

从3.1开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该...
  • czp11210
  • czp11210
  • 2016年07月23日 10:29
  • 1333

Spring Cache集成memcached

使用memcahed的客户端xmemcached实现Cache、CacheManager接口。
  • tianwei7518
  • tianwei7518
  • 2015年10月18日 15:16
  • 3000

cache 的设计与实现

本文整理自一下两篇博客:http://my.oschina.net/ScottYang/blog/298727http://my.oschina.net/u/866190/blog/188712 C...
  • zhushuai1221
  • zhushuai1221
  • 2016年07月14日 13:58
  • 587
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:spring-cache-1
举报原因:
原因补充:

(最多只允许输入30个字)