Spring cache是代码级的缓存,他一般是使用一个ConcurrentMap。也就是说实际上还是是使用JVM的内存来缓存对象的,那么肯定会造成大量的内存消耗。但是使用方便。
Redis 作为一个缓存服务器,是内存级的缓存。它是使用单纯的内存来进行缓存。
那么Spring cache +redis的好处显而易见了。既可以很方便的缓存对象,同时用来缓存的内存的是使用redis的内存,不会消耗JVM的内存,提升了性能。
回归正题:
Redis的安装:
1. 需要引用的依赖包(gradle):
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-json'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.slf4j:slf4j-migrator:1.8.0-beta2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
2. 配置:
# redis
spring.redis.host=192.168.5.129
spring.redis.port=6379
# pool settings:
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
## Whether to use the key prefix when writing to Redis.
spring.cache.redis.use-key-prefix=true
3. 配置Spring Cache管理Redis。
这里使用的是redis提供的序列化方式,有些类型在序列化时是不支持的):
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
/**
* 自定义生成redis-key
*
* @return
*/
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName()).append(".");
sb.append(method.getName()).append(".");
for (Object obj : objects) {
sb.append(obj.toString());
}
log.info("------> 自定义生成redis-key完成,keyGenerator=" + sb.toString());
return sb.toString();
}
};
}
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1)) // 设置缓存有效期一小时
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
.disableCachingNullValues();
RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
log.info("------> 自定义RedisCacheManager加载完成");
return redisCacheManager;
}
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(keySerializer());
redisTemplate.setHashKeySerializer(keySerializer());
redisTemplate.setValueSerializer(valueSerializer());
redisTemplate.setHashValueSerializer(valueSerializer());
log.info("------> 自定义RedisTemplate加载完成");
return redisTemplate;
}
private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer();
}
private RedisSerializer<Object> valueSerializer() {
return new Jackson2JsonRedisSerializer(Object.class);
}
使用@JsonComponent注解自定义序列化方式):
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
/**
* 自定义生成redis-key
*
* @return
*/
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName()).append(".");
sb.append(method.getName()).append(".");
for (Object obj : objects) {
sb.append(obj.toString());
}
log.info("------> 自定义生成redis-key完成,keyGenerator=" + sb.toString());
return sb.toString();
}
};
}
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
.transactionAware()
.build();
log.info("------> 自定义RedisCacheManager加载完成");
return redisCacheManager;
}
}
使用@JsonComponent注解 自定义User实体类Json格式序列化, spring boot框架在处理封装User实体类时自己会调用此序列化方法。
@JsonComponent
public class UserJsonSerializer extends JsonSerializer<User> {
@Override
public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("id",user.getId().toString());
jsonGenerator.writeStringField("username",user.getUsername());
jsonGenerator.writeStringField("password",user.getPassword());
jsonGenerator.writeEndObject();
}
}
注:该实体类必须实现Serializable 接口
@Document("t_user")
public class User implements Serializable {
@Id
private ObjectId id;
private String username;
private String password;
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
4. Spring Cache + Redis 的使用。
@Service
@CacheConfig
public class RedisServiceTest {
private MongoOperations mongoOperations;
public RedisServiceTest(MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
/**
* 注解@Cacheable中存在有以下几个元素
*
* value (也可使用 cacheNames) : 可看做命名空间,表示存到哪个缓存里了。
* key : 表示命名空间下缓存唯一key,使用Spring Expression Language(简称SpEL,详见参考文献[5])生成。
* condition : 表示在哪种情况下才缓存结果(对应的还有unless,哪种情况不缓存),同样使用SpEL
* @return
*/
@Cacheable(cacheNames="user",key = "'userAll'")
public List<User> getUserAll(){
long oneNow = System.currentTimeMillis();
List<User> all = mongoOperations.findAll(User.class);
System.out.println("耗时:" + (System.currentTimeMillis() - oneNow) + "ms");
return all;
}
/**
* 注解 @CacheEvict 中存在有以下几个元素
* - value (也可使用 cacheNames) : 同Cacheable注解,可看做命名空间。表示删除哪个命名空间中的缓存
* - allEntries: 标记是否删除命名空间下所有缓存,默认为false
* - key: 同Cacheable注解,代表需要删除的命名空间下唯一的缓存key。
*/
@CacheEvict(cacheNames="user",key = "'userAll'")
public void deleteRedis(){
}
}
开发中使用需要在Spring boot启动类开启缓存
@SpringBootApplication
@EnableCaching//开启缓存
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}