Spring Cache的基础

Spring Cache

文章目录

  • Spring Cache
    • 一、认识`Spring Cache`
    • 二、Spring Cache 抽象
      • 2.1 缓存注解
        • (1)`@Cacheable`
        • (2)`@CachePut`
        • (4)`@Caching`
        • (5) `@CacheConfig` 类级别的缓存
    • 三、实践经验

一、认识Spring Cache

第一步:配置缓存管理

    <context:component-scan base-package="com.hef"/>
    <cache:annotation-driven/>

    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
            set>
        property>
    bean>

第二步:使用缓存

    @Cacheable(cacheNames = "users")
    @Override
    public User getUserById(String userId) {
        System.out.println("real query user." + userId);
        return getFromDB(userId);
    }

    private User getFromDB(String userId){
        System.out.println("real querying db..." + userId);
        return new User.Builder().userId(userId).email("[email protected]").builder();
    }

二、Spring Cache 抽象

只有使用public定义的方法才可以被缓存。

缓存的本质就是键/值对集合。在默认情况下,缓存抽象使用方法签名及参数值作为一个键值,并将该键与方法调用的结果组成键/值对。

2.1 缓存注解

(1)@Cacheable

Spring首先在缓存中查找数据,如果没有则执行方法并缓存结果,然后返回数据

  • 缓存名必须提供;可以使用引号、Value或者cacheNames属性来定义名称

    @Cacheable(cacheNames = "users")
    @Cacheable(values = "users")
    @Cacheable(cacheNames = {"cache01","cache02"})
    
  • 键生成器

    默认情况下,缓存抽象使用方法签名及参数值作为一个键值,并将键与方法调用的结果组成键/值对。

    1)可以使用SpEL指定自定义键

        @Cacheable(cacheNames = "users", key = "#user.userCode")
        public User getUserByUser(User user) {
            System.out.println("real query user." + user.getUserCode());
            return getFromDB(user.getUserId());
        }
    

    2)可以通过实现org.springframework.cache.interceptor.KeyGenerator接口来定义个性化的Key生成器

    @Cacheable(cacheNames = "users", keyGenerator = "myKeyGenerator")
    

    3)带条件缓存

    @Cacheable(cacheNames = "users", key = "#user.userCode", condition = "#user.age >= 12")
    

(2)@CachePut

首先执行方法,然后将返回值放入缓存。当希望使用方法返回值更新缓存时,便可以选择这种方法。

####(3)@CacheEvict

负责从给定的缓存中移除一个值。

默认情况下,@CacheEvict注解在方法调用之后运行。

@allEntries属性 定义了是否移除缓存的所有条目,默认不移除这些条目;@beforeInvocation属性定义了在调用方法之前还是之后完成移除操作。

@CacheEvict(cacheNames = "users", allEntries = true, beforeInvocation = true)

(4)@Caching

@Caching是一个组注解,可以为一个方法定义提供基于@Cacheable@CacheEvict@CachePut注解的数组

@Caching(cacheable = {@Cacheable(value = "members", condition = "#obj instanceof T(com.hef.domain.Member)"),
            @Cacheable(value = "visitors", condition = "#obj instanceof T(com.hef.domain.Visitor)")})

(5) @CacheConfig 类级别的缓存

如果一个类中需要缓存的方法注解属性都相似,可以在类上通过@CacheConfig配置缓存,在方法上用@Cacheable标记。

三、实践经验

基于Proxy的Spring AOP带来的内部调用问题。

如果对象的方法是内部调用(this)而不是外部引用,则会导致代理失效,那么切面就失效,也就是说上面定义的各种注解,包括@Cacheable、@CachePut、@CacheEvict都会失效


    public User getUserByUser02(User user) {
        return getUserByUser(user);
    }

    @Cacheable(cacheNames = "users", key = "#user.userCode")
    public User getUserByUser(User user) {
        System.out.println("real query user." + user.getUserCode());
        return getFromDB(user.getUserId());
    }

在方法getUserByUser02()上调用getUserByUser(),发生了内部调用(this),所以没有使用代理类,导致Spring Cache失效。要避免这个问题,就要避免方法的内部调用,或者避免使用基于代理的AOP模式,也可以使用基于AspectJ的AOP模式来解决这个问题。

你可能感兴趣的:(Spring)