Spring Boot整合Redis的完整步骤

前言

实际 开发 中 缓存 处理是必须的,不可能我们每次客户端去请求一次 服务器 ,服务器每次都要去 数据库 中进行查找,为什么要使用缓存?说到底是为了提高系统的运行速度。将用户频繁访问的内容存放在离用户最近,访问速度最 快的 地方,提高用户的响 应速度,今天先来讲下在 springboot 中整合 redis 的详细步骤。

一、Spring Boot" title="Spring Boot">Spring Boot对Redis的支持

Spring对Redis的支持是使用Spring Data Redis来实现的,一般使用Jedis或者lettuce(默认),Java客户端在 org.springframework.boot.autoconfigure.data.redis(Spring Boot 2.x) 中redis的自动配置 AutoConfigureDataRedis

 

RedisAutoConfiguration提供了RedisTemplate与StringRedisTemplate(只针对键值都是字符型的数据)模板,其中注解 @ConditionalOnMissingBean 是关键,表明该Bean如果在Spring中已经存在,则忽略,如果没有存在则在此处注册由Spring管理,也就是说我们可以“重写”该bean,实现自己的RedisTemplate与StringRedisTemplate,事实上,是要需要重写的,理由如下:

  • 没有实现我们所需要的序列化;
  • 泛型总是<Object, Object>,大部分场景我们更需要<String, Object>。

@Bean

@ConditionalOnMissingBean(

name = {"redisTemplate"}

)

public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {

RedisTemplate<Object, Object> template = new RedisTemplate();

template.setConnectionFactory(redisConnectionFactory);

return template;

}

@Bean

@ConditionalOnMissingBean

public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {

StringRedisTemplate template = new StringRedisTemplate();

template.setConnectionFactory(redisConnectionFactory);

return template;

}

二、实战

1、添加依赖

1)需要spring-boot-starter-cache依赖,管理缓存

<!-- Spring Boot Cache -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-cache</artifactId>

</dependency>

2)需要spring-boot-starter-data-redis依赖(注:spring boot 2.x改为在data下),支持redis:主要以为Jedis客户端为主,排除默认的lettuce作为客户端的依赖

<!-- Redis Cache -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

<!-- 排除lettuce包,使用jedis代替-->

<exclusions>

<exclusion>

<groupId>io.lettuce</groupId>

<artifactId>lettuce-core</artifactId>

</exclusion>

</exclusions>

</dependency>

3)需要jedis-client依赖(注:Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突,最好使用2.9.x),使用jedis作为客户端

<!-- Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突 -->

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>2.9.0</version>

</dependency>

2、redis配置

创建RedisConfig配置类,增加@Configuration注解,同时开启缓存管理支持(添加注解@EnableCaching),继承CachingConfigurerSupport重写key生成策略

@Configuration

@EnableCaching

public class RedisConfig extends CachingConfigurerSupport {

/**

* 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key

* @return

*/

@Bean

@Override

public KeyGenerator keyGenerator() {

return (Object target, Method method, Object... params) -> {

StringBuilder sb = new StringBuilder();

sb.append(target.getClass().getName());

sb.append(method.getName());

for (Object obj : params) {

sb.append(obj.toString());

}

return sb.toString();

};

}

}

之后使用的application.yml配置文件,其中这里已经选择jedis作为客户端。

# redis 配置

redis:

port: 6379

# Redis服务器连接密码(默认为空)

password:

host: xxx.xxx.xxx.xxx

database: 0

jedis:

pool:

#连接池最大连接数(使用负值表示没有限制)

max-active: 300

# 连接池中的最小空闲连接

max-idle: 100

# 连接池最大阻塞等待时间(使用负值表示没有限制)

max-wait: 10000

# 连接超时时间(毫秒)

timeout: 5000

同时读取配置属性,注入JedisPoolConfig

/**

* redis配置属性读取

*/

@Value("${spring.redis.host}")

private String host;

@Value("${spring.redis.port}")

private int port;

@Value("${spring.redis.database}")

private int database;

@Value("${spring.redis.jedis.pool.max-idle}")

private int maxIdle;

@Value("${spring.redis.jedis.pool.max-wait}")

private long maxWaitMillis;

@Value("${spring.redis.jedis.pool.max-active}")

private int maxActive;

/**

* JedisPoolConfig配置

* @return

*/

@Bean

public JedisPoolConfig jedisPoolConfig() {

log.info("初始化JedisPoolConfig");

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

jedisPoolConfig.setMaxTotal(maxActive);

jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);

jedisPoolConfig.setMaxIdle(maxIdle);

return jedisPoolConfig;

}

3、实现序列化

针对RedisTemplate或StringRedisTemplate进行序列化,同时重写注册Bean

RedisTemplate默认使用JdkSerializationRedisSerializer,StringRedisTmeplate默认使用的是StringRedisSerializer。但都是不符合实际要求的

/**

* 重新实现RedisTemplate:解决序列化问题

* @param redisConnectionFactory

* @return

*/

@Bean

@SuppressWarnings({"rawtype", "unchecked"})

public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){

RedisTemplate<String, Object> template = new RedisTemplate();

template.setConnectionFactory(redisConnectionFactory);

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

ObjectMapper om = new ObjectMapper();

// 设置任何字段可见

om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

// 设置不是final的属性可以转换

om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

log.info("objectMapper: {}", om);

jackson2JsonRedisSerializer.setObjectMapper(om);

StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式

template.setKeySerializer(stringRedisSerializer);

// hash的key采用String的序列化方式

template.setHashKeySerializer(stringRedisSerializer);

// value序列化方式采用jackson序列化方式

template.setValueSerializer(jackson2JsonRedisSerializer);

// hash的value序列化方式采用jackson序列化方式

template.setHashValueSerializer(jackson2JsonRedisSerializer);

template.afterPropertiesSet();

template.setEnableTransactionSupport(true);

return template;

}

/**

* 重新实现StringRedisTmeplate:键值都是String的的数据

* @param redisConnectionFactory

* @return

*/

@Bean

public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

StringRedisTemplate template = new StringRedisTemplate();

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

template.setConnectionFactory(redisConnectionFactory);

StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式

template.setKeySerializer(stringRedisSerializer);

// hash的key采用String的序列化方式

template.setHashKeySerializer(stringRedisSerializer);

// value序列化方式采用jackson序列化方式

template.setValueSerializer(jackson2JsonRedisSerializer);

// hash的value序列化方式采用jackson序列化方式

template.setHashValueSerializer(jackson2JsonRedisSerializer);

return template;

}

4、创建Redis连接工厂,同时注册Bean

注意Spring Boot 1.x与Spring Boot 2.x的区别,已在代码中注释表明,Spring Boot 1.x使用的是JedisConnectionFactory 。而Spring Boot 2.x使用的是RedisStandaloneConfiguration ,之后传入JedisConnectionFactory返回Bean

/**

* 注入RedisConnectionFactory

* @return

*/

@Bean

public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {

log.info("初始化JedisConnectionFactory");

/* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置

JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);

jedisConnectionFactory.setHostName(host);

jedisConnectionFactory.setDatabase(database);*/

// JedisConnectionFactory配置hsot、database、password等参数

RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();

redisStandaloneConfiguration.setHostName(host);

redisStandaloneConfiguration.setPort(port);

redisStandaloneConfiguration.setDatabase(database);

// JedisConnectionFactory配置jedisPoolConfig

JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =

(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();

jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);

return new JedisConnectionFactory(redisStandaloneConfiguration);

}

5、完整的RedisConfig配置类

/**

*

* @author jian

* @date 2019/4/14

* @description

* 1) RedisTemplate(或StringRedisTemplate)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为<Object, Object>不是我们想要的类型)

* 所以自己实现RedisTemplate或StringRedisTemplate)

* 2) 采用RedisCacheManager作为缓存管理器

*

*/

@Configuration

@EnableCaching

public class RedisConfig extends CachingConfigurerSupport {

private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);

/**

* redis配置属性读取

*/

@Value("${spring.redis.host}")

private String host;

@Value("${spring.redis.port}")

private int port;

@Value("${spring.redis.database}")

private int database;

@Value("${spring.redis.jedis.pool.max-idle}")

private int maxIdle;

@Value("${spring.redis.jedis.pool.max-wait}")

private long maxWaitMillis;

@Value("${spring.redis.jedis.pool.max-active}")

private int maxActive;

/**

* JedisPoolConfig配置

* @return

*/

@Bean

public JedisPoolConfig jedisPoolConfig() {

log.info("初始化JedisPoolConfig");

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

jedisPoolConfig.setMaxTotal(maxActive);

jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);

jedisPoolConfig.setMaxIdle(maxIdle);

return jedisPoolConfig;

}

/**

* 注入RedisConnectionFactory

* @return

*/

@Bean

public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {

log.info("初始化JedisConnectionFactory");

/* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置

JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);

jedisConnectionFactory.setHostName(host);

jedisConnectionFactory.setDatabase(database);*/

// JedisConnectionFactory配置hsot、database、password等参数

RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();

redisStandaloneConfiguration.setHostName(host);

redisStandaloneConfiguration.setPort(port);

redisStandaloneConfiguration.setDatabase(database);

// JedisConnectionFactory配置jedisPoolConfig

JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =

(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();

jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);

return new JedisConnectionFactory(redisStandaloneConfiguration);

}

/**

* 采用RedisCacheManager作为缓存管理器

* @param connectionFactory

*/

@Bean

public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {

RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);

return redisCacheManager;

}

/**

* 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key

* @return

*/

@Bean

@Override

public KeyGenerator keyGenerator() {

return (Object target, Method method, Object... params) -> {

StringBuilder sb = new StringBuilder();

sb.append(target.getClass().getName());

sb.append(method.getName());

for (Object obj : params) {

sb.append(obj.toString());

}

return sb.toString();

};

}

/**

* 重新实现RedisTemplate:解决序列化问题

* @param redisConnectionFactory

* @return

*/

@Bean

@SuppressWarnings({"rawtype", "unchecked"})

public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){

RedisTemplate<String, Object> template = new RedisTemplate();

template.setConnectionFactory(redisConnectionFactory);

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

ObjectMapper om = new ObjectMapper();

// 设置任何字段可见

om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

// 设置不是final的属性可以转换

om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

log.info("objectMapper: {}", om);

jackson2JsonRedisSerializer.setObjectMapper(om);

StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式

template.setKeySerializer(stringRedisSerializer);

// hash的key采用String的序列化方式

template.setHashKeySerializer(stringRedisSerializer);

// value序列化方式采用jackson序列化方式

template.setValueSerializer(jackson2JsonRedisSerializer);

// hash的value序列化方式采用jackson序列化方式

template.setHashValueSerializer(jackson2JsonRedisSerializer);

template.afterPropertiesSet();

template.setEnableTransactionSupport(true);

return template;

}

/**

* 重新实现StringRedisTmeplate:键值都是String的的数据

* @param redisConnectionFactory

* @return

*/

@Bean

public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

StringRedisTemplate template = new StringRedisTemplate();

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

template.setConnectionFactory(redisConnectionFactory);

StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式

template.setKeySerializer(stringRedisSerializer);

// hash的key采用String的序列化方式

template.setHashKeySerializer(stringRedisSerializer);

// value序列化方式采用jackson序列化方式

template.setValueSerializer(jackson2JsonRedisSerializer);

// hash的value序列化方式采用jackson序列化方式

template.setHashValueSerializer(jackson2JsonRedisSerializer);

return template;

}

}

三、测试

1、编写redis工具类

虽然RedisTemplate与StringRedisTemplate模板有提供的主要数据访问方法:

  • opsForValue():操作只有简单属性的数据
  • opsForList():操作含有List的数据
  • opsForSet():操作含有set的数据
  • opsForHash():操作含有hash的数据
  • opsForZSet():操作含有有序set类型ZSet的数据

但是相关比较抽象,实现起来比较复杂,有必要进一步封装,比如使用redisTmeplate中的简单value的get操作:

Object result = null;

ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

result = operations.get(key);

但是封装之后,相对客户端用户来说比较明了

/**

* 读取缓存

*

* @param key

* @return

*/

public Object get(final String key) {

Object result = null;

ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

result = operations.get(key);

return result;

}

完整的简单工具类如下:

@Component

public class RedisUtils {

@Autowired

private RedisTemplate redisTemplate;

/**

* 批量删除对应的value

*

* @param keys

*/

public void remove(final String... keys) {

for (String key : keys) {

remove(key);

}

}

/**

* 批量删除key

*

* @param pattern

*/

public void removePattern(final String pattern) {

Set<Serializable> keys = redisTemplate.keys(pattern);

if (keys.size() > 0) {

redisTemplate.delete(keys);

}

}

/**

* 删除对应的value

*

* @param key

*/

public void remove(final String key) {

if (exists(key)) {

redisTemplate.delete(key);

}

}

/**

* 判断缓存中是否有对应的value

*

* @param key

* @return

*/

public boolean exists(final String key) {

return redisTemplate.hasKey(key);

}

/**

* 读取缓存

*

* @param key

* @return

*/

public Object get(final String key) {

Object result = null;

ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

result = operations.get(key);

return result;

}

/**

* 写入缓存

*

* @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) {

boolean result = false;

try {

ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

operations.set(key, value);

redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);

result = true;

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

}

2、Person实体类

需要注意的是一定要实现序列化,并且有序列化版本ID

public class Person implements Serializable {

private final long serialVersionUID = 1L;

private String id;

private String name;

private int age;

private String gender;

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getGender() {

return gender;

}

public void setGender(String gender) {

this.gender = gender;

}

@Override

public String toString() {

return "Person{" +

"id='" + id + '\'' +

", name='" + name + '\'' +

", age=" + age +

", gender='" + gender + '\'' +

'}';

}

}

3、编写测试类

Redis工具类Spring已经做了管理(增加@Compent注解),使用很简单,只需要注入RedisUtils即可

@RunWith(SpringRunner.class)

@SpringBootTest

public class RedisTest {

@Autowired

private RedisUtils redisUtils;

@Test

public void test(){

Person person = new Person();

person.setAge(23);

person.setId("001");

person.setName("Zhangsan");

redisUtils.set("person-001", person);

System.out.println(redisUtils.get("person-001"));

}

}

4、测试结果

在IDE控制台中:

 

在登录客户端后查看value值

 

总结

以上是 Spring Boot整合Redis的完整步骤 的全部内容, 来源链接: utcz.com/z/356894.html

回到顶部