Spring Cache缓存介绍

by admin on 2020年2月12日

Spring Framework 5.2 的第二个候选版本 RC2
已发布,可从里程碑仓库获取。

Spring 3.1
引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如
EHCache 或者
OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种
annotation,即能够达到缓存方法的返回对象的效果。

本次更新的内容有

新版本包含 63 个修复和改进,更新内容如下:

Spring 的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring
Expression Language)来定义缓存的 key 和各种
condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如
EHCache 集成。

  • 更新引用包版本
    • Microsoft.AspNetCore.Hosting.Abstractions 1.1.0
    • Microsoft.AspNetCore.Http.Abstractions 1.1.0
    • Microsoft.Extensions.PlatformAbstractions 1.1.0
    • System.Threading.Thread 4.3.0
    • System.Diagnostics.Process 4.3.0
    • System.Security.Cryptography.Algorithms 4.3.0
    • System.Runtime.Loader 4.3.0
    • System.Data.Common 4.3.0
    • System.IO.FileSystem.Watcher 4.3.0
    • NETStandard.Library 1.6.1
    • Microsoft.Data.Sqlite 1.1.0
    • Microsoft.EntityFrameworkCore 1.1.0
    • Microsoft.EntityFrameworkCore.Design 1.1.0
    • Microsoft.EntityFrameworkCore.InMemory 1.1.0
    • Microsoft.EntityFrameworkCore.Sqlite 1.1.0
    • Microsoft.EntityFrameworkCore.SqlServer 1.1.0
    • Microsoft.Extensions.DependencyModel 1.1.0
    • Npgsql 3.1.9
    • Npgsql.EntityFrameworkCore.PostgreSQL 1.1.0
    • Pomelo.EntityFrameworkCore.MySql 1.0.1
  • 降低引用包版本
    • 澳门新葡亰信誉平台游戏,MySql.Data 6.9.9 (新版本会造成asp.net项目无法启动)
  • 改进从Http请求获取参数的处理
    • IHttpRequest.Get支持从json内容获取
    • IHttpRequest.Get支持获取提交的文件
    • IHttpRequest.GetAll支持从json内容获取
  • 支持Range头
    • 只在可以Seek的流上支持
  • 改进NHibernate的RawUpdate和RawQuery,允许传递null参数
  • Bug修复
    • 修复部分情况下出现的与System.Drawing的冲突错误
    • 修复HttpContextCache在没有Http上下文时会出错的问题

New Features

  • 使用 start byte=resource-byte-count
    可能无效的部分内容请求 #23576
  • 支持使用 ReflectionTestUtils.invokeMethod()
    调用静态方法 #23504
  • 通过检查 classpath 来检测要使用的
    ClientHttpConnector #23493
  • 从 ContentCachingResponseWrapper 中删除 statusCode
    状态 #23490
  • 修复 LGTM.com
    报告的“数组索引超出范围”问题 #23485
  • 通过 @AliasFor 配置的显式属性覆盖不支持通过组件扫描获取的组件 #23402
  • 提供一种在不初始化 FactoryBeans 的情况下预测 bean
    类型的方法 #23374
  • 在 TransactionContextManager 中预分配
    NoTransactionException #23360
  • 在 StopWatch 中使用 System.nanoTime() 而不是
    System.currentTimeMillis() #23235
  • 正确编码和解码
    “message/x.rsocket.routing.v0” #23137
  • 添加对 Coroutines
    事务的支持 #22915

其特点总结如下:

本次更新兼容以前的版本,旧版本的项目使用nuget更新即可

Bug Fixes

  • 无法在 @TestPropertySource 位置使用占位符之后的相对路径 #23544
  • Spring Webflux 5.2.0.M2 – Kotlin 协同程序 –
    ServerRequest.awaitPrincipal 始终为
    null #22986

还包括不少文档和依赖更新,详情可查看更新说明及下载地址。

(文/开源中国)    

1.通过少量的配置 annotation 注释即可使得既有代码支持缓存

2.支持开箱即用
Out-Of-The-Box,即不用安装和部署额外第三方组件即可使用缓存

3.支持 Spring Express Language,能使用对象的任何属性或者方法来定义缓存的
key 和 condition

4.支持 AspectJ,并通过其实现任何方法的缓存支持

5.支持自定义 key 和自定义缓存管理者,具有相当的灵活性和扩展性

一、基于注解的支持

Spring为我们提供了几个注解来支持Spring
Cache。其核心主要是@Cacheable、@CachePut
和@CacheEvict。使用@Cacheable标记的方法在执行后Spring
Cache将缓存其返回结果,@CachePut主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和
@Cacheable不同的是,它每次都会触发真实方法的调用,而使用@CacheEvict标记的方法会在方法执行前或者执行后移除Spring
Cache中的某些元素。

1.@Cacheable

@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

value:缓存的名称,在 spring
配置文件中定义,必须指定至少一个。如@Cacheable(value=”mycache”)
或者@Cacheable(value={”cache1”,”cache2”}

key:缓存的 key,可以为空,如果指定要按照 SpEL
表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。如@Cacheable(value=”testcache”,key=”#userName”)

condition:缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者
false,只有为 true
才进行缓存。如@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

注:除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。

属性名称

描述

示例

methodName

当前方法名

#root.methodName

method

当前方法

#root.method.name

target

当前被调用的对象

#root.target

targetClass

当前被调用的对象的class

#root.targetClass

args

当前方法参数组成的数组

#root.args[0]

caches

当前被调用的方法使用的Cache

#root.caches[0].name

2.@CachePut
在支持Spring
Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
3.@CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。
allEntries:是否清空所有缓存内容,缺省为 false,如果指定为
true,则方法调用后将立即清空所有缓存。如:@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为
true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存。如:@CachEvict(value=”testcache”,beforeInvocation=true)
其他参数和@Cacheable相同
4.@Caching
@Caching注解可以让我们在一个方法或者类上同时指定多个Spring
Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。如:
@Caching(cacheable = @Cacheable(“users”), evict = {
@CacheEvict(“cache2”),@CacheEvict(value = “cache3”, allEntries = true)
})

二、实例

使用map集合实现缓存管理,演示spring cache的使用。

1.创建缓存对象实例

package org.springframework.cache.demo;

import java.io.Serializable;

//缓存对象
public class User implements Serializable{
 /**
  *
  */
 private static final long serialVersionUID = 1L;
 private int id;
 private String name;
 
 public User(){
 }
 
 public User(String name){
  this.name= name;
 }
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}
2.对象服务实现类

package org.springframework.cache.demo;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;

/**
 * 业务服务
 *
 */
public class UserService {

 @Cacheable(value = “userCache”,key=”#userName”)
 // 使用了一个缓存名叫 userCache
 public User getUserByName(String userName) {
  // 方法内部实现不考虑缓存逻辑,直接实现业务
  return getFromDB(userName);
 }

 @CacheEvict(value = “userCache”, key = “#user.name”)
 // 清空 accountCache 缓存
 public void updateUser(User user) {
  updateDB(user);
 }

 @CacheEvict(value = “userCache”, allEntries =
true,beforeInvocation=true)
 // 清空 accountCache 缓存
 public void reload() {
 }

 private User getFromDB(String userName) {
  System.out.println(“查询数据库…” + userName);
  return new User(userName);
 }

 private void updateDB(User user) {
  System.out.println(“更新数据库数据…” + user.getName());
 }
}
3.缓存实现

package org.springframework.cache.demo.mycache;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;

public class MyCache implements Cache {

 private String name;
 private Map<String, Object> store = new
ConcurrentHashMap<String, Object>();;

 public MyCache() {
 }

 public MyCache(String name) {
  this.name = name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public void clear() {
  store.clear();
 }

 public void evict(Object obj) {
 }

 public ValueWrapper get(Object key) {
  ValueWrapper result = null;
  Object thevalue = store.get(key);
  if (thevalue != null) {
   result = new SimpleValueWrapper(thevalue);
  }
  return result;
 }

 public <T> T get(Object key, Class<T> clazz) {
  return clazz.cast(store.get(key));
 }

 public String getName() {
  return name;
 }

 public Object getNativeCache() {
  return store;
 }

 public void put(Object key, Object value) {
  store.put((String) key, value);
 }

 public ValueWrapper putIfAbsent(Object key, Object value) {
  put(key, value);
  return new SimpleValueWrapper(value);
 }
}
4.spring配置

<beans xmlns=””
 xmlns:xsi=””
xmlns:cache=””
 xmlns:p=””
 xsi:schemaLocation=”

“>
 <!–
启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效
–>
 <cache:annotation-driven cache-manager=”cacheManager” />

 <bean id=”userService”
class=”org.springframework.cache.demo.UserService” />

 <!– generic cache manager –>
 <bean id=”cacheManager”
class=”org.springframework.cache.support.SimpleCacheManager”>
  <property name=”caches”>
   <set>
    <bean class=”org.springframework.cache.demo.mycache.MyCache”
     p:name=”userCache” />
   </set>
  </property>
 </bean>
</beans>5.运行类

package org.springframework.cache.demo.mycache;

import org.springframework.cache.demo.User;
import org.springframework.cache.demo.UserService;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyMain {

 @SuppressWarnings(“resource”)
 public static void main(String[] args) {
  ApplicationContext context = new
ClassPathXmlApplicationContext(“spring-cache-mycache.xml”);
  UserService userService = context.getBean(UserService.class);
  // 第一次查询,应该走数据库
  System.out.print(“第一次查询…”);
  userService.getUserByName(“hello”);
  // 第二次查询,应该不查数据库,直接返回缓存的值
  System.out.println(“第二次查询…”);
  userService.getUserByName(“hello”);
  System.out.println();
  System.out.println(“==============”);

  // 更新某个记录的缓存,首先构造两个用户记录,然后记录到缓存中
  User user1 = userService.getUserByName(“user1”);
  // 开始更新其中一个
  user1.setId(1000);
  userService.updateUser(user1);
  // 因为被更新了,所以会查询数据库
  userService.getUserByName(“user1”);
  // 再次查询,应该走缓存
  userService.getUserByName(“user1”);
  // 更新所有缓存
  userService.reload();
  System.out.println(“清楚所有缓存”);
  // 查询数据库
  userService.getUserByName(“user1”);
  userService.getUserByName(“user2”);
  // 查询缓存
  userService.getUserByName(“user1”);
  userService.getUserByName(“user2”);
 }
}
运行结果:

第一次查询…查询数据库…hello
第二次查询…

==============
查询数据库…user1
更新数据库数据…user1
清楚所有缓存
查询数据库…user1
查询数据库…user2

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/135128.htm

澳门新葡亰信誉平台游戏 1

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图