irpas技术客

SpringBoot整合Redis_Xxxyfeng_springboot整合redis

未知 571

我们之所以要学习Redis,是要令我们Java程序更加有效率,我们在使用数据库的时候给它加上一个缓存中间件,就是用来提高我们程序的效率的,那么当然,Redis还是要集成到我们SpringBoot项目里面的!!

整合也非常简单,新建一个SpringBoot项目,导入相关依赖

?只要把这些选项勾起来,那么SpringBoot在创建项目的时候就会自动帮我们导入所需要的依赖!

<!-- redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 热部署依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

到我们SpringBoot2.x版本,其内置的Redis中间件再也不是Jedis了,而是换成了lettuce。我们点进redis依赖就可以发现

那么lettuce是什么呢,其与Jedis有什么区别呢?

lettuce: Lettuce 是 一种可伸缩,线程安全,完全非阻塞的Redis客户端,多个线程可以共享一个RedisConnection,它利用Netty NIO 框架来高效地管理多个连接,从而提供了异步和同步数据访问方式,用于构建非阻塞的反应性应用程序。

Jedis: Jedis 在实现上是直连 redis server,多线程环境下非线程安全,除非使用连接池,为每个 redis实例增加 物理连接。 这种方式更加类似于我们 BIO 一条线程连一个客户端,并且是阻塞式的,会一直连接着客户端等待客户端的命令

那么导入这个redis,根据我们之前学习SpringBoot,我们知道一定有一个Properties配置类去配置我们的Redis的

那么我们在IDEA中双击shift查看

点进这个类中查看可以配置什么 ?

@Configuration(proxyBeanMethods = false) @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { // redis的模板实例,可以帮助我们快速操作redis @Bean // 如果这个名为redisTemplate实例不存在的话,该bean生效,那么我们可以代替SpringBoot,自定义我们的redis模板实例!!! @ConditionalOnMissingBean(name = "redisTemplate") @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } // 因为我们很多情况都是操作String类型的数据,那么这个类帮我们也配置了String的redis模板供我们使用! // 其方法与上面的redisTemplate一样 @Bean @ConditionalOnMissingBean @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }

我们点进这个RedisProperties类中查看相关配置!

可以看到我们可以在SpringBoot配置文件中配置以下东西

@ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { /** * 可以配置使用的db下标 */ private int database = 0; /** * 这个配置可以让我们连接到远程的redis中。例如: * redis://user:password@example.com:6379 */ private String url; /** * Redis服务端的主机名 */ private String host = "localhost"; /** * Login username of the redis server. */ private String username; /** * Login password of the redis server. */ private String password; /** * Redis的端口号 */ private int port = 6379; /** * 是否开启安全认证 */ private boolean ssl; /** * Read timeout. */ private Duration timeout; /** * Connection timeout. */ private Duration connectTimeout; /** * Client name to be set on connections with CLIENT SETNAME. */ private String clientName; /** * Type of client to use. By default, auto-detected according to the classpath. */ private ClientType clientType; private Sentinel sentinel; private Cluster cluster; }

其中主机名和端口号都有默认值,如果我们连自己的电脑,那么这两个配置都可以不用修改!

我们这里不用修改配置文件,就使用默认的即可!

测试连接

那么从我们导入redis的依赖,就可以使用了,我们现在来测试一下连接!

//自动注入redisTemplate @Autowired private RedisTemplate redisTemplate; @Test void contextLoads() { //获取redis数据库连接对象 RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory(); RedisConnection connection = connectionFactory.getConnection(); // 往Redis服务端中设置一个String类型的key,值为zhangsan redisTemplate.opsForValue().set("name","zhangsan"); // 获取并打印这个key的值 System.out.println(redisTemplate.opsForValue().get("name")); }

我们还需要在window系统中开启我们的Redis服务端!

测试结果

zhangsan # 控制台成功打印出key的值

我们连接Redis客户端,再获取这个key

127.0.0.1:6379> ping # 测试连接 PONG 127.0.0.1:6379> get name # 获取key中的value "zhangsan" # 返回zhangsan,测试成功!

那么现在我们能在SpringBoot项目中使用Redis了,但是我们如果存中文的话会发生乱码!例如

redisTemplate.opsForValue().set("name","张三"); //往value中添加中文 System.out.println(redisTemplate.opsForValue().get("name"));

那么再次测试Redis

张三 # 控制台可以输出中文

Redis客户端获取key

127.0.0.1:6379> keys * 1) "\xac\xed\x00\x05t\x00\x04name" # key乱码了

我们在分析Redis配置文件中也发现了我们的RedisTemplate时可以让我们配置的,那么默认的RedisTemplate给我们配置了什么?

点进这个类中看一下

public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { ....... @SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null; @SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null; @SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null; @SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null; public void afterPropertiesSet() { super.afterPropertiesSet(); boolean defaultUsed = false; if (defaultSerializer == null) { // 默认的序列化方式为JDK中自带的序列化 defaultSerializer = new JdkSerializationRedisSerializer( classLoader != null ? classLoader : this.getClass().getClassLoader()); } if (enableDefaultSerializer) { // 因为我们并没有设置其序列化的实例,那么在创建这个RedisTemplate实例的时候,全部都默认成了JDK的序列化方式! if (keySerializer == null) { keySerializer = defaultSerializer; defaultUsed = true; } if (valueSerializer == null) { valueSerializer = defaultSerializer; defaultUsed = true; } if (hashKeySerializer == null) { hashKeySerializer = defaultSerializer; defaultUsed = true; } if (hashValueSerializer == null) { hashValueSerializer = defaultSerializer; defaultUsed = true; } } if (enableDefaultSerializer && defaultUsed) { Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized"); } if (scriptExecutor == null) { this.scriptExecutor = new DefaultScriptExecutor<>(this); } initialized = true; } ........ }

我们可以知道,如果我们不配置RedisTemplate的序列化方式,默认的是使用JDK中的序列化方式,那么我们点进这个JdkSerializationRedisSerializer类中看看

点进深层我们发现,里面其实创建了一个序列化转换器,而转换器默认的构造方法是JDK默认的序列化工具,其实现了Serializer接口

void serialize(T object, OutputStream outputStream) throws IOException;

因为我们java使用ISO-8859-1编码进行传输数据的,那么我们传输字符串的话,那么编解码会不一致,一定会出现乱码!!!

所以我们得自己重写一个RedisTemplate来修改默认的序列化方式!

我们从上面分析可以知道,当我们的类中出现以redisTemplate命名的bean的时候,SpringBoot的配置将不会生效!

那我们来接管一下这个redisTemplate类

// 标志为配置类 @Configuration public class RedisConfig { // 把这个bean的name设置为redisTemplate,这样我们才能全面接管redisTemplate! @Bean(name = "redisTemplate") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); // jackson序列化所有的类 Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // jackson序列化的一些配置 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance); Jackson2JsonRedisSerializer.setObjectMapper(om); // String的序列化 StringRedisSerializer stringSerializer = new StringRedisSerializer(); //将我们的key采用String的序列化方式 template.setKeySerializer(stringSerializer); //将我们的hash的key也采用String的序列化方式 template.setHashKeySerializer(stringSerializer); //value采用jackson序列化方式 template.setValueSerializer(Jackson2JsonRedisSerializer); //hash的value也采用jackson序列化方式 template.setHashValueSerializer(Jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; }

?我们继续来编写一个简单的实体类,其中这个类必须要实现序列化!!!!不然直接报错,因为这个类不能序列化

@Component @AllArgsConstructor @NoArgsConstructor @Data //我们的实体类全部需要序列化! public class User implements Serializable { private String name; private int age; }

我们测试一下

User user = new User("李四",3); redisTemplate.opsForValue().set("lisi",user);

我们这里使用Redis Desktop Manager可视化工具来查看结果

我们看到,key和value不再乱码了,乱码问题解决!!!

我们这里不使用cmd命令行去查看结果的原因是,其编码格式是使用GBK编码的,value还是会乱码!

Redis工具类

我们在SpringBoot中去操作Redis总是要写这么几个方法

redisTemplate.opsForValue().set();

那么当我们频繁操作Redis的时候,这就会显得代码很冗余,加大了维护成本!

所以我们要编写自己的工具类去封装Redis中的方法!

这里只截取一部分,只要注入我们的redisTemplate,封装里面常用的的方法即可

@Service public class RedisUtil { @Autowired private RedisTemplate redisTemplate; /** * 写入缓存 * * @param key * @param value * @return */ public boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 写入缓存设置时效时间 * * @param key * @param value * @return */ public boolean set(final String key, Object value, Long expireTime, TimeUnit timeUnit) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, timeUnit); result = true; } catch (Exception e) { e.printStackTrace(); } return result; }


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。