这一节,我们将整合redis,并用将session交由redis保存。为之后的集群和分布式开发做准备。
整合redis 配置 这里介绍redis的单机配置,集群配置之后再说。默认你已安装了redis。
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency >
1 2 3 4 5 spring: redis: host: 127.0 .0 .1 port: 6380 password: 123456
没错,只要这两步操作,就可以在项目中使用redis啦。
用junit测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 @RunWith (SpringRunner.class)@SpringBootTest (classes = DemoApplication.class)public class Test1 { @Autowired private StringRedisTemplate stringRedisTemplate; @Test public void test1 () { String value1 = "hahaha" ; stringRedisTemplate.opsForValue().set("test" , value1); Assert.assertEquals(value1, stringRedisTemplate.opsForValue().get("test" )); } }
运行一下test1,看看是否测试通过了。再在redis里看看是否键和值都有并对应上了。
使用注解 上面这种手动操作存储、读取数据的用法,一般我们在系统中很少用到。我们可以在方法上加@CacheConfig
,@Cacheable
,@CachePut
,@CacheEvict
这几个缓存注解(关于这几个注解的作用,可以自己查一下,比较简单这里就不介绍了),自动进行缓存操作。不过在使用这几个注解之前,需要在DemoApplication类加上@EnableCaching
这个注解来使缓存注解生效。
加上@EnableCaching
注解后测试一下,在UserService中加入以下方法:
1 2 3 4 5 6 7 8 @Cacheable (cacheNames = "User" , key = "#id" )public RespInfo<User> getUser (Long id) { if (id == null ) { return RespInfo.error("请输入用户ID" ); } User user = userMapper.selectByPrimaryKey(id); return RespInfo.success(user); }
test类:
1 2 3 4 5 6 7 8 9 10 11 12 @RunWith (SpringRunner.class)@SpringBootTest (classes = DemoApplication.class)@Slf 4jpublic class Test1 { @Autowired private UserService userService; @Test public void test1 () { RespInfo respInfo = userService.getUser(1L ); } }
先在getUser()中打个断点,再Debug两次test1。第一次运行时,断点生效,运行成功后,redis里生成了key为User::1
的数据。说明注解已生效,并把结果存入redis。第二次运行时,断点没有生效,运行成功,返回值和第一次运行的一样。说明我们是从redis中读取的数据,并没有经过数据库查询。
RedisCacheConfig 上面已经基本完成了缓存的使用。但是还有两个小问题:1.我们给方法加缓存,每次都要定义一个缓存key,比较麻烦。2.我们存在redis里的数据默认使用jdk的序列化方法,该方法效率低、序列化后需要的内存较大、缓存的类必须要实现Serializable
接口,而且数据可读性不高。所以我们需要定义一个通用的key生成方法,并用Jackson序列化方法代替默认的序列化方法。
我们创建RedisCacheConfig类继承CachingConfigurerSupport
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 @Configuration public class RedisCacheConfig extends CachingConfigurerSupport { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public RedisTemplate redisTemplate () { StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean @Override public CacheManager cacheManager () { RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); configuration = configuration.entryTtl(Duration.ofHours(6 )).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(configuration).build(); return cacheManager; } @Bean @Override public KeyGenerator keyGenerator () { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(":" ).append(method.getName()); sb.append(":" ).append(getParamsString(params)); return sb.toString(); }; } private String getParamsString (Object params) { try { String s = new Gson().toJson(params); return MD5Util.MD5(s); } catch (Exception e) { e.printStackTrace(); } return "null" ; } }
UserService修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Autowired private RedisTemplate redisTemplate;@Cacheable (cacheNames = "Demo" )public RespInfo<User> getUser (Long id) { if (id == null ) { return RespInfo.error("请输入用户ID" ); } User user = userMapper.selectByPrimaryKey(id); redisTemplate.opsForValue().set("test" , user); return RespInfo.success(user); }
再按照之前上面的测试操作,测试一下是否成功。如果成功的话,发现redis多了两个key:
1 2 Demo::com.tt.study.demo.service.UserService:getUser:35DBA5D75538A9BBE0B4DA4422759A0E test
使用get key查看一下,发现都是json格式的数据,可读性完爆之前的。
整合spring session(使用redis存session)
1 2 3 4 5 <dependency > <groupId > org.springframework.session</groupId > <artifactId > spring-session-data-redis</artifactId > </dependency >
1 2 3 @EnableRedisHttpSession (redisNamespace = "Demo" , maxInactiveIntervalInSeconds = 3600 )
没错,又是只要两步操作,就可以了。
测试一下,添加一个controller:
1 2 3 4 5 6 7 8 9 @RequestMapping ("/login" )@ResponseBody public Object login (User user, HttpSession session) { RespInfo<User> respInfo = userService.login(user); if (respInfo.isSuccess()) { session.setAttribute("user_session" , respInfo.getData()); } return respInfo; }
请求一次,查看redis,发现多了3个key:
1 2 3 Demo:sessions:expires:8165ce0b-f18e-4184-8b6f-10774dd46c67 Demo:sessions:8165ce0b-f18e-4184-8b6f-10774dd46c67 Demo:expirations:1521549420000
Ok,现在session已经交给redis保存了,我们之后做集群也不用担心session的问题了。