spring-cache使用简介

spring-cache使用简介

简介

缓存是实际工作中经常使用的一种提高性能的方法, 我们会在很多场景下来使用缓存,而spring-cache就是一种简单的实现。阅读本文你应该能够短时间内掌握spring带来的强大缓存技术,在非常少的配置下就可以给既有代码提供缓存能力。

配置

首先自行引用spring的jar包

  1. spring-cache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
    <cache:annotation-driven cache-manager="cacheManager"/>
    <!-- 配置spring缓存 -->
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <list>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCache">
                    <constructor-arg value="data"/>
                </bean>
            </list>
        </property>
    </bean>
    <bean id="springCache" class="com.yaojiafeng.common.cache.SpringCache"/>
    </beans>
  2. SpringCache.java

    package com.yaojiafeng.common.cache;
    
    import org.springframework.cache.annotation.CacheEvict;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
    * Created by yaojiafeng on 2017/4/18 下午3:22.
    */
    public class SpringCache {
    
    /**
    * 加缓存
    * <p>
    * value=data 代表1级key 从EhCacheCacheManager获取Cache
    * key=#id 代表2级key 从Cache获取
    *
    * @param id
    * @return
    */
    @Cacheable(value = "data", key = "#id")
    public String getData(String id) {
    return id + ":" + System.currentTimeMillis();
    }
    
    /**
    * 清缓存
    *
    * @param id
    */
    @CacheEvict(value = "data", key = "#id")
    public void setData(String id) {
    }
    
    public static void main(String[] args) {
    ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("/cache/spring-cache.xml");
    SpringCache springCache = (SpringCache) classPathXmlApplicationContext.getBean("springCache");
    String data = springCache.getData("1");
    System.out.println(data);
    data = springCache.getData("1");
    System.out.println(data);
    springCache.setData("1");
    String data1 = springCache.getData("1");
    System.out.println(data1);
    String data2 = springCache.getData("2");
    System.out.println(data2);
    }
    }

运行SpringCache.java的main方法查看结果

从结果可见第二次getData是从缓存获取,第三次getData又不是从缓存获取,测试结果正确。

原理解析

  1. 首先解析spring xml自定义命名空间

        <cache:annotation-driven cache-manager="cacheManager"/>

    这行配置对应的解析类是AnnotationDrivenCacheBeanDefinitionParser(原理请搜索spring自定义命名空间的解析过程),该类的parse方法内的registerCacheAdvisor方法读取xml配置,通过AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element)并往spring容器注册了InfrastructureAdvisorAutoProxyCreator这个bean的后置处理器(用于动态代理,织入切面),并通过SpringCachingConfigurer.registerCacheAdvisor(element, parserContext)往spring容器注册BeanFactoryCacheOperationSourceAdvisor通知器(通知器包含了CacheInterceptor通知和AnnotationCacheOperationSource切点匹配器),这里特别说明默认的cache-manager="cacheManager",则通过上面的SimpleCacheManager注入,SimpleCacheManager是具体的存储缓存的地方,我们可以根据选择灵活替换。

  2. cacheManager配置

     <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
            <property name="caches">
                <list>
                    <bean class="org.springframework.cache.concurrent.ConcurrentMapCache">
                        <constructor-arg value="data"/>
                    </bean>
                </list>
            </property>
        </bean>

    cacheManager有很多实现,这里我选择最简单的SimpleCacheManager

  3. SpringCache的getData方法

    @Cacheable(value = "data", key = "#id")
    public String getData(String id) {
        return id + ":" + System.currentTimeMillis();
    }

    该方法加了Cacheable注解,则会在spring装载SpringCache这个bean的时候被BeanFactoryCacheOperationSourceAdvisor通知器的切点匹配到,所以我们从spring容器获取的SpringCache为动态代理的bean,织入的通知器为BeanFactoryCacheOperationSourceAdvisor,具体的通知为CacheInterceptor,所以可知调用getData方法会走CacheInterceptor的invoke方法(环绕通知),他内部会调用execute方法,从当前拦截的方法获取spring-cache的相关注解(Cacheable、CacheEvict、CachePut、Caching,每个注解都有对应的功能),并解析注解找到对应的cacheManager、cacheResolver、keyGenerator等信息,并且会通过condition配置判断当前缓存是否需要操作, getData上有Cacheable注解,该注解首先判断当前缓存有无数据有则获取,无则调用到我们的代理方法,然后插入到缓存中(详见CacheInterceptor#invoke),其中Cacheable的value属性对应具体的缓存名,key则代表缓存中的key(支持spel表达式从参数动态生成key).

  4. SpringCache的setData方法

    @CacheEvict(value = "data", key = "#id")
    public void setData(String id) {
    }

    该方法加了CacheEvict注解,也会被BeanFactoryCacheOperationSourceAdvisor的切点匹配到,然后走CacheInterceptor拦截器,再调用代理类的方法后,清除对应的缓存。

  5. 核心代码

    所有的加缓存,清缓存等操作都在此方法实现。

  6. 概括总结

    spring-cache延续了注解和AOP搭配使用的风格,与spring事务如出一辙,不管是xml配置和注入的bean都大同小异,所以核心知识点如下:
    • spring自定义命名空间
    • AOP

猜你喜欢

转载自www.cnblogs.com/yaojf/p/10833647.html
今日推荐