springboot使用redis做缓存
根据springboot对缓存的自动配置原理:
如果没有工程中没有引入其它的CacheManager,默认使用ConcurrentMapCacheManager;
ConcurrentMapCacheManager管理的缓存为ConcurrentMapCache;
ConcurrentMapCache利用ConcurrentHashMap来保存缓存数据;
1.安装redis
使用Docker安装;
查看redis镜像名:
docker search redis
可以看到:
docker公共仓库docker.hub中redis的镜像名为docker.io/redis;
可以简写为redis;
从docker公共仓库中拉取redis镜像到本地:
docker pull redis
查看是否拉取成功
docker images
可以看到:
redis镜像已经安装到本地仓库,版本是目前最新的latest
启动redis:
docker run -d -p 6379:6379 --name myredis docker.io/redis
使用docker run命令启动:
-d ->后台启动
-p ->端口转发,把docker容器的端口转发到主机端口,否则不能访问;redis默认监听6379端口;
--name ->自定义的docker容器名;
后面接要启动的docker镜像名;
是否启动成功:
docker ps
2.引入redis依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
3.配置redis
yml配置:
spring:
redis:
host: 192.168.1.193 #redis主机地址
4.使用RestTemplate操作redis
原理:
引入redis后,自动配置类RedisAutoConfiguration生效;
用@Bean注解给ioc容器中添加了两个组件:RedisTemplate、StringRedisTemplate;
这两个组件都是用来操作redis的;
RedisTemplate中的泛型<Object,Object>分别代表redis中的key和value;
由于往redis中操作字符串的场景较多,专门提供了StringRedisTemplate;
5. 使用StringRedidsTemplate给redis中插入一条字符串数据
@RunWith(SpringRunner.class) @SpringBootTest(classes = Cache01Application.class) public class TestRedis { @Autowired private StringRedisTemplate strTemp; @Test public void go(){ strTemp.opsForValue().append("gun", "M4-A1"); } }
结果:
使用redis可视化工具查看
6.使用RedisTemplate保存对象
踩坑:
实体类必需是可序列化的;
java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.example.demo.entity.Employee]
解决:
Employee实现Serializable接口;
测试类:
@RunWith(SpringRunner.class) @SpringBootTest(classes = Cache01Application.class) public class TestRedis { @Autowired(required = false) private EmployeeDao dao; @Autowired private RedisTemplate<Object, Object> temp; @Test public void go(){ Employee emp1 = dao.get(1); temp.opsForValue().set("emp", emp1); } }
结果:
对象被序列化成为二进制保持在redis中;
默认使用java自带的序列化器;
7.以json的格式保存对象
两种实现方式:
1】对象转json字符串保存;(利用转换工具,FastJson、Jackson等)
2】更换默认的序列化器;
1)更换序列化器
RedisTemplate默认使用jdk自带序列化器;
更换序列化器:
定义一个配置类,利用@Bean向ioc容器注入一个RedisTemplate实例;
修该实例的默认序列化器;
原理:
redis的自动配置类中向ioc容器中注入RedisTemplate实例时使用了@ConditionalOnMissingBean(name = {"redisTemplate"}) ;
@Bean注入组件时默认方法名即为bean名;
可以用自己注入的RedisTemplate实例替换自动配置类注入的;
RedisTemplate的key和value都是用默认序列化器做序列号;
只需要替换掉默认序列化器即可;
配置类:
@Configuration public class RedisConfig { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); //替换默认序列化器 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class); template.setDefaultSerializer(serializer); return template; } }
测试类:
使用junit4测试
@RunWith(SpringRunner.class) @SpringBootTest(classes = Cache01Application.class) public class TestRedis { @Autowired(required = false) private EmployeeDao dao; @Autowired private RedisTemplate<Object, Object> temp; @Test public void go(){ Employee emp1 = dao.get(1); temp.opsForValue().set("emp", emp1); } }
结果:
8.注解式缓存
注解式缓存在没有引入其它CacheManager时,默认使用CurrnetHashMap来保存数据;
引入redis后将会使用RedisCacheManager;
也就是说注解式缓存将使用Redis来保持数据;
dao:
使用@Cacheable标记get方法,当方法被调用时,会缓存方法的返回值
public interface EmployeeDao { @Cacheable(cacheNames = {"emp"}) public Employee get(Integer id); }
controller:
@RestController public class EmployeeController { @Autowired(required = false) //加required=false,防止报红 private EmployeeDao dao; @RequestMapping("/get/{id}") public Employee get(@PathVariable("id") Integer id){ return dao.get(id); } }
测试:
浏览器请求get接口,将导致dao层的get方法被调用,缓存注解生效,redis中会添加一条数据;
由于默认使用jdk序列化器,redis中缓存的是二进制数据
1)以json格式缓存
原理:
缓存的自动配置类:CacheAutoConfiguration用注解@Import向ioc容器中注入Redis缓存配置类
RedisCacheConfiguration利用@Bean注解,向ioc容器中注入RedisCacheManager;
条件是:@ConditionalOnMissingBean({CacheManager.class})
RedisCacheManager默认使用jdk的序列化器来序列化key和value;因此redis中保存的是二进制;
为了用json序列化器,可以在容器中注入一个CacheManager,这样自动注入的RedisCacheManager就不会生效;
新建一个配置类:
@Configuration public class RedisConfig { //使用json序列化器的RedisCacheManager @Bean public CacheManager cacheManager(RedisConnectionFactory factory){ RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofDays(1)) .disableCachingNullValues() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build(); } }
测试:
浏览器访问