首页 > 技术文章 > springboot使用redis做缓存

ShiningArmor 2020-06-15 10:31 原文

根据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();
    }
}
 
测试:
    浏览器访问
 
 
 
 
 

推荐阅读