當不指定緩存的key時,SpringBoot會使用SimpleKeyGenerator生成key。java
查看源碼能夠發現,它是使用方法參數組合生成的一個key。web
諸以下面紅框的代碼,SpEL實際上能夠寫很是複雜的生成規則。redis
在 @Configuration 標註的類中,能夠根據本身設計的規則自定義鍵生成器。spring
/** * 新的鍵生成規則 */ @Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator(){ public Object generate(Object target, Method method, Object... params){ StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("::" + method.getName() + ":"); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; }
上面自定義的鍵生成器鍵的生成規則是:包名+方法名+參數列表。數據庫
RedisSerializer redis序列化的接口類apache
OxmSerializer xml到object的序列化/反序列化json
StringRedisSerializer string字符串的序列化/反序列化數組
JacksonJsonRedisSerializer json到object的序列化/反序列化緩存
Jackson2JsonRedisSerializer json到object的序列化/反序列化app
JdkSerializationRedisSerializer java對象的序列化/反序列化
JdkSerializationRedisSerializer:JDK自帶的序列化方式、存儲的字符串內容在序列化的狀況下偏長,會佔用過多的內存
OxmSerializer:序列化的時間相對較長
Jackson2JsonRedisSerializer:json數據格式、序列化時間和序列化以後內容的長度都要優於前兩種
/** * RedisTemplate 使用 Jackson2JsonRedisSerializer 做爲序列化器 * @return */ @Bean public RedisTemplate<String, String> redisTemplate() { StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; }
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.7</version> </dependency>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ding.data</groupId> <artifactId>RedisCacheCase</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <boot.version>1.3.5.RELEASE</boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>${boot.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> <version>${boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>${boot.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.7</version> </dependency> <!-- <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency> --> </dependencies> </project>
spring: cache: #緩存名稱 #cache-names: guavaDemo #緩存最大數量500條, 緩存失效時間 6個小時 #guava.spec: maximumSize=500,expireAfterWrite=360m # REDIS (RedisProperties) redis : host : localhost # server host port : 6379 # connection port password : 123 database : 1 pool.max-idle : 8 # pool settings ... pool.min-idle : 1 pool.max-active : 8 pool.max-wait : -1
package com.ding.data; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ding.data.cache.DataCache; /** * 是Spring Boot項目的核心註解,主要是開啓自動配置 */ @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan @RestController // 開啓緩存 @EnableCaching public class RedisCacheCase { @Autowired private DataCache dataCache; public static void main(String[] args) { SpringApplication.run(RedisCacheCase.class, args); } @RequestMapping("/put") public String put(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()) + " : value is " + dataCache.put(id, value) ; } @RequestMapping("/get") public String query(Long id){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()) + " : value is " +dataCache.query(id) ; } @RequestMapping("/remove") public String remove(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dataCache.remove(id) ; return sdf.format(new Date()) + " : success " ; } }
package com.ding.data.config; import java.lang.reflect.Method; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class MyRedisCacheConfig extends CachingConfigurerSupport{ @Autowired private JedisConnectionFactory jedisConnectionFactory; @Bean public CacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate()); redisCacheManager.setDefaultExpiration(86400); return redisCacheManager; } /** * RedisTemplate 使用 Jackson2JsonRedisSerializer 做爲序列化器 * @return */ @Bean public RedisTemplate<String, String> redisTemplate() { StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } /** * 新的鍵生成規則 */ @Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator(){ public Object generate(Object target, Method method, Object... params){ StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("::" + method.getName() + ":"); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } }
package com.ding.data.cache; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; @Component public class DataCache { private Map<Long, String> dataMap = new HashMap<Long, String>(); /** * 初始化 */ @PostConstruct public void init() { dataMap.put(1L, "張三"); dataMap.put(2L, "李四"); dataMap.put(3L, "王五"); } /** * 查詢 * 若是數據沒有緩存,那麼從dataMap裏面獲取,若是緩存了, * 那麼從redisDemo裏面獲取 * 而且將緩存的數據存入到 redisDemo裏面 * 其中key 爲 #id+dataMap */ // @Cacheable(value="redisDemo" ,key="#id + 'dataMap'") @Cacheable(value="redisDemo") public String query(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : query id is " + id); return dataMap.get(id); } /** * 插入 或者更新 * 插入或更新數據到dataMap中 * 而且緩存到 redisDemo中 * 若是存在了那麼更新緩存中的值 * 其中key 爲 #id+dataMap */ // @CachePut(value="redisDemo" ,key="#id + 'dataMap'") @CachePut(value="redisDemo") public String put(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id); dataMap.put(id, value); // data persistence return value; } /** * 刪除 * 刪除dataMap裏面的數據 * 而且刪除緩存redisDemo中的數據 * 其中key 爲 #id+dataMap */ // @CacheEvict(value="redisDemo" , key="#id + 'dataMap'") @CacheEvict(value="redisDemo") public void remove(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : remove id is "+ id + " data"); dataMap.remove(id); // data remove } }
依次訪問:
http://localhost:8080/get?id=1
http://localhost:8080/get?id=2
http://localhost:8080/put?id=1&value=meixi
http://localhost:8080/put?id=1&value=neimaer
http://localhost:8080/put?id=1&value=cluo
查看Redis內存的內容,以下(由於Redis的database參數用的1,因此用的是Redis中的db1庫)
與代碼的邏輯是相符的,可是出現了新的問題,除了 @Cacheable 註解的方法仍然起到緩存的做用,其餘的緩存方法實際上沒起做用。這主要是由於如今緩存鍵生成的規則不具有重複利用性,實際項目須要根據需求對鍵生成規則進行修改的。
package com.ding.data.config; import java.lang.reflect.Method; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.stereotype.Component; @Component public class MyKeyGenerator implements KeyGenerator{ public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("::" + "query" + ":" + params[0].toString()); return sb.toString(); } }
/** * 插入 或者更新 * 插入或更新數據到dataMap中 * 而且緩存到 redisDemo中 * 若是存在了那麼更新緩存中的值 * 其中key 爲 #id+dataMap */ // @CachePut(value="redisDemo" ,key="#id + 'dataMap'") @CachePut(value="redisDemo",keyGenerator="myKeyGenerator") public String put(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id); dataMap.put(id, value); // data persistence return value; }
意思就是說明這個方法的鍵生成規則採用myKeyGenerator這個類
依次訪問:
http://localhost:8080/get?id=1
http://localhost:8080/put?id=1&value=meixi
查看Redis數據庫中的數據
可見改造後@CachePut 標註的方法也起做用了。
可是如今代碼仍然太「死性」,沒法應用於實際項目。要想應用於實際項目,還須要根據具體需求進行設計。