spring的缓存抽象

spring的缓存抽象

详情参看:《SpringBoot基础系列-SpringCache使用》

支持

ConcurrentMap、EhCache、Caffeine、JCache

接口

org.springframework.cache.Cache
org.springframework.cache.CacheManager

那些缓存的注解

@EnableCaching 开启缓存功能

  • @Cacheable 定义缓存,用于触发缓存
  • @CacheEvict 定义清除缓存,触发缓存清除
  • @CachePut 定义更新缓存,触发缓存更新
  • @Caching 组合定义多种缓存功能
  • @CacheConfig 定义公共设置,位于class之上,如缓存名字

@EnableCaching

用于开启基于注解的缓存功能
@EnableCaching的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {

	/**
	 * 用于设置使用哪种代理方式,默认是基于接口的jdk动态代理(false)
	 * 设置为true,则使用基于继承的cglib动态代理
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 设置切面织入方式(设置面向切面编程的实现方式)
	 * 默认使用动态代理的方式织入,当然也可以设置为AspectJ的方式来实现aop
	 */
	AdviceMode mode() default AdviceMode.PROXY;

	/**
	 * 设置在一个切入点存在多个通知的时候各个通知的执行顺序,默认为最低优先级
	 * 其中数字越大优先级越低,这里默认为最低优先级,Integer.MAX_VALUE整数最大值
	 * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
	 */
	int order() default Ordered.LOWEST_PRECEDENCE;
}

/**上面选择的枚举值*/
public enum AdviceMode {
    PROXY,
    ASPECTJ
}
public interface Ordered {
    int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
    int getOrder();
}

示列:

@EnableCaching
@Configuration
public class CacheConfig {
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("default")));
        return cacheManager;
    }
}

注意:在springboot中使用springCache可以由自动配置功能来完成CacheManager的注册,自动根据拥有的缓存系统注册对应的缓存管理器,也可以手动指定

@EnableCaching 等同于下面的xml配置

<beans>
    <cache:annotation-driven/>
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager>
        <property name="caches">
            <set>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean>
                    <property name="name" value="default"/>
                </bean>
            </set>
        </property>
    </bean>
</beans>

@Cacheable

标注在方法上,方法返回结果被缓存起来
标注在类上,类里所有方法返回结果都被缓存起来
涉及的方法每次被调用前都会触发缓存校验,校验指定参数的缓存是否已存在,存在,直接返回缓存结果;否则执行方式,方法执行结果保存到缓存中。

源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {

	/**指定缓存名称,与cacheNames()方法效果一样*/
	@AliasFor("cacheNames")
	String[] value() default {};

	/** 指定缓存名称,与vale()方法效果一样*/
	@AliasFor("value")
	String[] cacheNames() default {};

	/**
	 * 使用SpEL(Spring Expression Language)表达式手动指定缓存键的组合方式,默认情况使用所有的参数来组合成键,除非自定义了keyGenerator
	 * SpEl表达式可以根据上下文环境来获取到指定的数据
	 * #root.method:用于获取当前方法的Method实例
	 * #root.target:用于获取当前方法的target实例
	 * #root.caches:用于获取当前方法关联的缓存
	 * #root.methodName:用于获取当前方法的名称
	 * #root.targetClass:用于获取目标类类型
	 * #root.args[1]:获取当前方法的第二个参数,等同于:#p1和#a1和#argumentName
	 */
	String key() default "";

	/**
	 * 自定义键生成器,定义了该方法后,上面的key方法自动失效,这个键生成器是:
	 * org.springframework.cache.interceptor.KeyGenerator,函数式接口
	 * 只有一个generate方法,我们通过自定义的逻辑来实现自定义的key生成策略
	 */
	String keyGenerator() default "";

	/**
	 * 设置自定义的CacheManager(缓存管理器),自动生成一个CacheResolver(缓存解析器)
	 * 与cacheResolver()方法设置互斥
	 */
	String cacheManager() default "";

	/** 设置一个自定义的缓存解析器 */
	String cacheResolver() default "";

	/**
	 * 设置执行缓存的条件,如果条件不满足,方法返回的结果就不会被缓存,默认无条件全部缓存
	 * 使用SpEL(Spring Expression Language)来定义条件
	 * SpEl表达式可以根据上下文环境来获取到指定的数据
	 * #root.method:用于获取当前方法的Method实例
	 * #root.target:用于获取当前方法的target实例
	 * #root.caches:用于获取当前方法关联的缓存
	 * #root.methodName:用于获取当前方法的名称
	 * #root.targetClass:用于获取目标类类型
	 * #root.args[1]:获取当前方法的第二个参数,等同于:#p1和#a1和#argumentName
	 */
	String condition() default "";

	/**
	 * 用于禁用缓存功能,如果设置的条件满足,就不缓存结果
	 * 与上面condition()方法不同之处在于,该方法执行在当前方法调用结束,结果出来之后,
	 * 因此它除了可以使用上面condition所能使用的SpEl表达式外
	 * 还可以使用#result来获取方法的执行结果,根据结果的不同来决定是否缓存
	 */
	String unless() default "";

	/**
	 * 是否对多个针对同一key执行缓存加载操作的线程进行同步,默认不同步
	 * 这个功能需要明确确定所使用的缓存工具是否支持该功能,否则不要滥用
	 */
	boolean sync() default false;

}

示列:

@Service
@Log4j2
public class AnimalService {
    @Autowired
    private AnimalRepository animalRepository;
    
	//@Cacheable("animalById")
	//缓存名称是animalByid,缓存的key是id的值
    @Cacheable(value = "animalById", key = "#id")
    public ResponseEntity<Animal> getAnimalById(final int id){
        return ResponseEntity.ok(animalRepository.selectById(id));
    }
    
}

注意:一般缓存名称必须要有,因为这个是区别于其他方法的缓存的唯一方法;
key = “#id” 指定当前方法缓存保存时的键组成,默认情况下使用所有的参数组合而成,这样可以有效区分不同参数的缓存。
也可以使用SpEl表达式手动指定

自定义一个keyGenerator

public class AnimalKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder sb = new StringBuilder("animal-");
        sb.append(target.getClass().getSimpleName()).append("-").append(method.getName()).append("-");
        for (Object o : params) {
            String s = o.toString();
            sb.append(s).append("-");
        }
        return sb.deleteCharAt(sb.lastIndexOf("-")).toString();
    }
}
缓存结构

每个缓存名称下存在多个缓存条目
缓存条目对应不同参数调用方法时生成的缓存
所以一个缓存名称并不是一个缓存,而是一系列缓存

缓存名称
	- 缓存条目(key:value- 缓存条目(key:value

@CachePut

更新缓存,无论结果是否已经缓存,都会在方法执行结束后插入缓存,相当于更新缓存。一般用在更新方法上
源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {

	/**指定缓存名称,与cacheNames()方法效果一样*/
	@AliasFor("cacheNames")
	String[] value() default {};

	/** 指定缓存名称,与vale()方法效果一样*/
	@AliasFor("value")
	String[] cacheNames() default {};

	/**
	 * 使用SpEL(Spring Expression Language)表达式手动指定缓存键的组合方式,默认情况使用所有的参数来组合成键,除非自定义了keyGenerator
	 * SpEl表达式可以根据上下文环境来获取到指定的数据
	 * #root.method:用于获取当前方法的Method实例
	 * #root.target:用于获取当前方法的target实例
	 * #root.caches:用于获取当前方法关联的缓存
	 * #root.methodName:用于获取当前方法的名称
	 * #root.targetClass:用于获取目标类类型
	 * #root.args[1]:获取当前方法的第二个参数,等同于:#p1和#a1和#argumentName
	 */
	String key() default "";

	/**
	 * 自定义键生成器,定义了该方法后,上面的key方法自动失效,这个键生成器是:
	 * org.springframework.cache.interceptor.KeyGenerator,函数式接口
	 * 只有一个generate方法,我们通过自定义的逻辑来实现自定义的key生成策略
	 */
	String keyGenerator() default "";

	/**
	 * 设置自定义的CacheManager(缓存管理器),自动生成一个CacheResolver(缓存解析器)
	 * 与cacheResolver()方法设置互斥
	 */
	String cacheManager() default "";

	/** 设置一个自定义的缓存解析器 */
	String cacheResolver() default "";

	/**
	 * 设置执行缓存的条件,如果条件不满足,方法返回的结果就不会被缓存,默认无条件全部缓存
	 * 使用SpEL(Spring Expression Language)来定义条件
	 * SpEl表达式可以根据上下文环境来获取到指定的数据
	 * #root.method:用于获取当前方法的Method实例
	 * #root.target:用于获取当前方法的target实例
	 * #root.caches:用于获取当前方法关联的缓存
	 * #root.methodName:用于获取当前方法的名称
	 * #root.targetClass:用于获取目标类类型
	 * #root.args[1]:获取当前方法的第二个参数,等同于:#p1和#a1和#argumentName
	 */
	String condition() default "";

	/**
	 * 用于禁用缓存功能,如果设置的条件满足,就不缓存结果
	 * 与上面condition()方法不同之处在于,该方法执行在当前方法调用结束,结果出来之后,
	 * 因此它除了可以使用上面condition所能使用的SpEl表达式外
	 * 还可以使用#result来获取方法的执行结果,根据结果的不同来决定是否缓存
	 */
	String unless() default "";

}

示列:

@Service
@Log4j2
public class AnimalService {
    @Autowired
    private AnimalRepository animalRepository;
    
    @CachePut(value = "animalById", key = "#animal.id")
    public ResponseEntity<Animal> updateAnimal(final Animal animal){
        Wrapper<Animal> animalWrapper = new UpdateWrapper<>();
        ((UpdateWrapper<Animal>) animalWrapper).eq("id",animal.getId());
        animalRepository.update(animal, animalWrapper);
        return ResponseEntity.ok(this.getAnimalById(animal.getId()));
    }
    
}

这里指定更新缓存,value是缓存名称,更新上文@Cacheable示列方法 getAnimalById查询操作的同一缓存,而且key设置为id也与上面的key设置对应

@CacheEvict

删除缓存

源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {

	/**指定缓存名称,与cacheNames()方法效果一样*/
	@AliasFor("cacheNames")
	String[] value() default {};

	/** 指定缓存名称,与vale()方法效果一样*/
	@AliasFor("value")
	String[] cacheNames() default {};

	/**
	 * 使用SpEL(Spring Expression Language)表达式手动指定缓存键的组合方式,默认情况使用所有的参数来组合成键,除非自定义了keyGenerator
	 * SpEl表达式可以根据上下文环境来获取到指定的数据
	 * #root.method:用于获取当前方法的Method实例
	 * #root.target:用于获取当前方法的target实例
	 * #root.caches:用于获取当前方法关联的缓存
	 * #root.methodName:用于获取当前方法的名称
	 * #root.targetClass:用于获取目标类类型
	 * #root.args[1]:获取当前方法的第二个参数,等同于:#p1和#a1和#argumentName
	 */
	String key() default "";

	/**
	 * 自定义键生成器,定义了该方法后,上面的key方法自动失效,这个键生成器是:
	 * org.springframework.cache.interceptor.KeyGenerator,函数式接口
	 * 只有一个generate方法,我们通过自定义的逻辑来实现自定义的key生成策略
	 */
	String keyGenerator() default "";

	/**
	 * 设置自定义的CacheManager(缓存管理器),自动生成一个CacheResolver(缓存解析器)
	 * 与cacheResolver()方法设置互斥
	 */
	String cacheManager() default "";

	/** 设置一个自定义的缓存解析器 */
	String cacheResolver() default "";

	/**
	 * 设置执行缓存的条件,如果条件不满足,方法返回的结果就不会被缓存,默认无条件全部缓存
	 * 使用SpEL(Spring Expression Language)来定义条件
	 * SpEl表达式可以根据上下文环境来获取到指定的数据
	 * #root.method:用于获取当前方法的Method实例
	 * #root.target:用于获取当前方法的target实例
	 * #root.caches:用于获取当前方法关联的缓存
	 * #root.methodName:用于获取当前方法的名称
	 * #root.targetClass:用于获取目标类类型
	 * #root.args[1]:获取当前方法的第二个参数,等同于:#p1和#a1和#argumentName
	 */
	String condition() default "";

	/**指定当前缓存名称下的所有缓存是否全部删除,默认为false*/
	boolean allEntries() default false;

	/** 指定删除缓存的操作是否在方法调用之前完成,默认是false,表示先调用方法,再执行缓存删除*/
	boolean beforeInvocation() default false;

}

示列:

@Service
@Log4j2
public class AnimalService {
    @Autowired
    private AnimalRepository animalRepository;
    //...
    @CacheEvict(value = "animalById", key = "#id")
    public ResponseEntity<Integer> deleteAnimalById(final int id){
        return ResponseEntity.ok(animalRepository.deleteById(id));
    }
    //...
}

@Caching

多个缓存操作的组合,包括针对不同缓存名称的相同操作等
源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
	/**指定多个缓存设置操作*/
	Cacheable[] cacheable() default {};
	/**指定多个缓存更新操作*/
	CachePut[] put() default {};
	/**指定多个缓存失效操作*/
	CacheEvict[] evict() default {};

}

示列:

@Service
@Log4j2
public class AnimalService {
    @Autowired
    private AnimalRepository animalRepository;
    //...
    @Caching(
        evict = {
            @CacheEvict(value = "animalById", key = "#id"),
            @CacheEvict(value = "animals", allEntries = true, beforeInvocation = true)
        }
    )
    public ResponseEntity<Integer> deleteAnimalById(final int id){
        return ResponseEntity.ok(animalRepository.deleteById(id));
    }
    @Cacheable("animals")
    public ResponseEntity<Page<Animal>> getAnimalPage(final Animal animal, final int pageId, final int pageSize){
        Page<Animal> page = new Page<>();
        page.setCurrent(pageId);
        page.setSize(pageSize);
        return ResponseEntity.ok((Page<Animal>) animalRepository.selectPage(page,packWrapper(animal, WrapperType.QUERY)));
    }
    //...
}

@CacheConfig

标注于类上,进行一些公共的缓存相关配置
源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {
    /**设置统一的缓存名,适用于整个类中的方法全部是针对同一缓存名操作的情况*/
    String[] cacheNames() default {};
    /**设置统一个键生成器,免去了每个缓存设置中单独设置*/
    String keyGenerator() default "";
    /**设置统一个自定义缓存管理器*/
    String cacheManager() default "";
    /**设置统一个自定义缓存解析器*/
    String cacheResolver() default "";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值