本文介绍spring boot项目集成redis缓存的过程。java
redis是一个开源的内存NOSQL数据库,在web开发中主要被用于数据缓存。通常在高并发的状况下,web服务器接受访问时,直接从数据库加载是慢的,须要把经常使用数据缓存到redis中,提升加载速度和并发能力。mysql
建立一个spring boot项目,配置redis各相关 bean,实现几个接口,经过两种方式测试redis缓存:linux
如没有开发环境,可参考前面章节:[spring boot 开发环境搭建(Eclipse)]。git
打开Eclipse,建立spring boot的spring starter project项目,选择菜单:File > New > Project ...
,弹出对话框,选择:Spring Boot > Spring Starter Project
,在配置依赖时,勾选web
、redis
,完成项目建立。github
须要用到commons-pool2
库,在pom.xml
中添加依赖web
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
在application.properties
文件中配置redis服务器的链接redis
## REDIS (RedisProperties) # Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=192.168.0.99 # Redis服务器链接端口 spring.redis.port=6379 # Redis服务器链接密码(默认为空) spring.redis.password= # 链接池最大链接数(使用负值表示没有限制) spring.redis.lettuce.pool.max-active=8 # 链接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.lettuce.pool.max-wait=-1 # 链接池中的最大空闲链接 spring.redis.lettuce.pool.max-idle=8 # 链接池中的最小空闲链接 spring.redis.lettuce.pool.min-idle=0
项目目录结构以下图,咱们添加了几个类,下面将详细介绍。spring
首先使用@EnableCaching
开启以注解方式使用缓存。sql
而后配置redis相关的bean数据库
/** * @description redis配置 配置序列化方式以及缓存管理器 */ @EnableCaching // 开启缓存 @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfig { /** * 配置自定义redisTemplate * * @param connectionFactory * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); template.setValueSerializer(jackson2JsonRedisSerializer()); //使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(jackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; } /** * json序列化 * @return */ @Bean public RedisSerializer<Object> jackson2JsonRedisSerializer() { //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper); return serializer; } /** * 配置缓存管理器 * @param redisConnectionFactory * @return */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 生成一个默认配置,经过config对象便可对缓存进行自定义配置 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 设置缓存的默认过时时间,也是使用Duration设置 config = config.entryTtl(Duration.ofMinutes(1)) // 设置 key为string序列化 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 设置value为json序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer())) // 不缓存空值 .disableCachingNullValues(); // 设置一个初始化的缓存空间set集合 Set<String> cacheNames = new HashSet<>(); cacheNames.add("timeGroup"); cacheNames.add("user"); // 对每一个缓存空间应用不一样的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put("timeGroup", config); configMap.put("user", config.entryTtl(Duration.ofSeconds(120))); // 使用自定义的缓存配置初始化一个cacheManager RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) // 必定要先调用该方法设置初始化的缓存名,再初始化相关的配置 .initialCacheNames(cacheNames) .withInitialCacheConfigurations(configMap) .build(); return cacheManager; } /** * 缓存的key是 包名+方法名+参数列表 */ @Bean public KeyGenerator keyGenerator() { return (target, method, objects) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("::" + method.getName() + ":"); for (Object obj : objects) { sb.append(obj.toString()); } return sb.toString(); }; } }
public class User { private long id; private String nickname; private String mobile; @JsonProperty(access = Access.WRITE_ONLY) //在输出的Json数据中隐藏密码,只能输入不输出 private String password; private String role; public User(long id, String nickname, String mobile, String password, String role) { this.id = id; this.nickname = nickname; this.mobile = mobile; this.password = password; this.role = role; } public User() { super(); } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } }
@Cacheable
- 代表对应方法的返回结果能够被缓存,首次调用后,下次就从缓存中读取结果,方法不会再被执行了。@CachePut
- 更新缓存,方法每次都会执行@CacheEvict
- 清除缓存,方法每次都会执行由于主要的业务逻辑在服务层实现,通常会把缓存注解加在服务层的方法上。
下面几个服务层的方法会加缓存注解:
@Cacheable
@CacheEvict
UserSevice.java 接口
public interface UserService { public User getUserById(long userId); public User updateUserNickname(long userId, String nickname); }
UserServiceImpl.java 实现类
@Service("userService") public class UserServiceImpl implements UserService { private static final org.slf4j.Logger log = LoggerFactory.getLogger(UserServiceImpl.class); private User user = new User(1l, "abc1", "13512345678", "123456", "role-user"); @Cacheable(value = "user", key= "#userId") @Override public User getUserById(long userId) { log.info("加载用户信息"); return user; } @CacheEvict(value = "user", key= "#userId") @Override public User updateUserNickname(long userId, String nickname) { user.setNickname(nickname); return user; } }
@RestController @EnableAutoConfiguration @RequestMapping("/user") public class UserController { // 注入service类 @Resource private UserService userService; // 注入RedisTemplate @Resource private RedisTemplate<String, Object> redis; // 读取用户信息,测试缓存使用:除了首次读取,接下来都应该从缓存中读取 @RequestMapping(value="{id}", method=RequestMethod.GET, produces="application/json") public User getUser(@PathVariable long id) throws Exception { User user = this.userService.getUserById(id); return user; } // 修改用户信息,测试删除缓存 @RequestMapping(value = "/{id}/change-nick", method = RequestMethod.POST, produces="application/json") public User changeNickname(@PathVariable long id) throws Exception{ String nick = "abc-" + Math.random(); User user = this.userService.updateUserNickname(id, nick); return user; } // 使用RedisTemplate访问redis服务器 @RequestMapping(value="/redis", method=RequestMethod.GET, produces="application/json") public String redis() throws Exception { // 设置键"project-name",值"qikegu-springboot-redis-demo" redis.opsForValue().set("project-name", "qikegu-springboot-redis-demo"); String value = (String) redis.opsForValue().get("project-name"); return value; } }
Eclipse左侧,在项目根目录上点击鼠标右键弹出菜单,选择:run as -> spring boot app
运行程序。 打开Postman访问接口,
同时监控redis服务器。
监控redis服务器,使用
redis-cli
命令连上服务器,而后使用monitor
命令开始监控:
运行结果以下:
获取用户信息
redis中的数据,能够看到数据经过SET
指令保存进redis了
屡次获取用户信息,能够看到经过GET
指令从redis中读取缓存
修改用户信息
redis中的缓存被删除了
测试使用RedisTemplate访问redis服务器
redis中的数据变化