Spring boot集成Redis
使用Spring boot和Redis集成,可以使用默认的RedisAutoConfiguration类加载properties文件的配置。同时也可以自己写代码实现或者是xml配置文件实现Redis的配置。例子中配置文件没有采用yml 而是properties。
使用Spring boot的AutoConfig加载
新建Spring boot工程
登录http://start.spring.io/ ,在Dependencies中输入Redis并选择,然后点击Generate Project生成工程,将下载的Maven工程导入Eclipse等开发工具即可。
pom文件依赖的jar包
只要引入spring-boot-starter-data-redis就可以实现redis的使用。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置application.properties, 使用的单点模式,sentinel模式的配置注释掉了:
#################redis基础配置#################
spring.redis.database=5
spring.redis.host=19.29.80.50
spring.redis.password=admin.1231
spring.redis.port=7001
# 连接超时时间 单位 ms(毫秒)
spring.redis.timeout=3000
#################redis线程池设置#################
# 连接池中的最大空闲连接,默认值也是8。
spring.redis.pool.max-idle=500
#连接池中的最小空闲连接,默认值也是0。
spring.redis.pool.min-idle=50
# 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
spring.redis.pool.max-active=2000
# 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
spring.redis.pool.max-wait=1000
#################redis哨兵设置#################
# Redis服务器master的名字
#spring.redis.sentinel.master=master8026
# redis-sentinel的配置地址和端口
#spring.redis.sentinel.nodes=10.189.80.25:26379,10.189.80.26:26379,10.189.80.27:26378
Redis服务类
直接使用RedisAutoConfiguration加载properties文件的配置 RedisTemplate泛型不能使用具体的类型。
服务类中用了缓存标签@CachePut和@Cacheable,其中 value字段的标签是@AliasFor(“cacheNames”) ,在后面的RedisCacheManager 中利用cacheName对不同的类型设置不同的过期时间。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
/**
* Alias for {@link #cacheNames}.
*/
@AliasFor("cacheNames")
String[] value() default {};
......省略其他
}
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private Set<User> users = new HashSet<User>();
private Set<City> cities = new HashSet<City>();
@CachePut(value = "user", key = "'User:'+#user.id")
public User addUser(User user) {
users.add(user);
return user;
}
@Cacheable(value = "user", key = "'User:'+#id")
public User addUser(String id, String name, int age) {
User user = new User(id, name, age);
users.add(user);
return user;
}
@Cacheable(value = "user", key = "'User:'+#id")
public User getStudent(String id) {
System.out.println("not in redis cache");
for (User user : users) {
if (user.getId().equals(id)) {
return user;
}
}
return null;
}
@CachePut(value = "city", key = "'City:'+#city.id")
public City addCity(City city) {
cities.add(city);
return city;
}
}
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootRedisApplicationTests {
private Logger logger=LoggerFactory.getLogger(this.getClass());
@Autowired
private RedisService service;
@Test
public void contextLoads() {
User user=new User("student1","name",19);
service.addUser(user);
logger.info("RedisTest执行完成,return {}",service.getStudent(user.getId()).getId());
City city=new City("city1","400500","深圳");
service.addCity(city);
}
}
自己写代码加载配置
spring boot加载Redis配置的源码
可以看到spring-boot-autoconfigure的源代码中是使用RedisAutoConfiguration来加载Redis的配置的。 其中RedisAutoConfiguration会加载properties文件的前缀为“spring.redis”的属性。其中“spring.redis.sentinel”是哨兵模式的配置,“spring.redis.cluster”是集群模式的配置。代码较长就不贴了。
自己通过代码方式实现加载:
添加注解@EnableCaching 启用注解缓存,cacheManager方法中对不同的cacheName设置不同的过期时间。
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.min-idle}")
private int minIdle;
/**
* 注解@Cache key生成规则
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(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();
}
};
}
/**
* 注解@Cache的管理器,设置过期时间的单位是秒
* @Description:
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
Map<String, Long> expires=new HashMap<String, Long>();
expires.put("user", 6000L);
expires.put("city", 600L);
cacheManager.setExpires(expires);
// Number of seconds before expiration. Defaults to unlimited (0)
cacheManager.setDefaultExpiration(600); //设置key-value超时时间
return cacheManager;
}
/**
* redis模板,存储关键字是字符串,值是Jdk序列化
* @Description:
* @param factory
* @return
*/
@Bean
public RedisTemplate<?,?> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<?,?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误;
RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
//JdkSerializationRedisSerializer序列化方式;
JdkSerializationRedisSerializer jdkRedisSerializer=new JdkSerializationRedisSerializer();
redisTemplate.setValueSerializer(jdkRedisSerializer);
redisTemplate.setHashValueSerializer(jdkRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* redis连接的基础设置
* @Description:
* @return
*/
@Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(host);
factory.setPort(port);
factory.setPassword(password);
//存储的库
factory.setDatabase(database);
//设置连接超时时间
factory.setTimeout(timeout);
factory.setUsePool(true);
factory.setPoolConfig(jedisPoolConfig());
return factory;
}
/**
* 连接池配置
* @Description:
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
// jedisPoolConfig.set ...
return jedisPoolConfig;
}
/**
* redis数据操作异常处理
* 这里的处理:在日志中打印出错误信息,但是放行
* 保证redis服务器出现连接等问题的时候不影响程序的正常运行,使得能够出问题时不用缓存
* @return
*/
@Bean
@Override
public CacheErrorHandler errorHandler() {
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
@Override
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
logger.error("redis异常:key=[{}]",key,e);
}
@Override
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
logger.error("redis异常:key=[{}]",key,e);
}
@Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
logger.error("redis异常:key=[{}]",key,e);
}
@Override
public void handleCacheClearError(RuntimeException e, Cache cache) {
logger.error("redis异常:",e);
}
};
return cacheErrorHandler;
}
}
使用xml配置文件加载
对于大多数之前使用xml文件配置的同学,还想沿用xml文件配置Redis,只要在application中引入xml文件即可。
@ImportResource(locations={"classpath:spring/spring-redis.xml"})
@SpringBootApplication
public class SpringBootRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRedisApplication.class, args);
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="minIdle" value="${redis.pool.minIdle}" />
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="usePool" value="true"></property>
<property name="hostName" value="${redis.ip}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.password}" />
<property name="timeout" value="${redis.timeout}" />
<property name="database" value="${redis.default.db}"></property>
<constructor-arg ref="jedisPoolConfig" />
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="KeySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
</property>
<property name="ValueSerializer">
<bean
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
</property>
<property name="HashKeySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
</property>
<property name="HashValueSerializer">
<bean
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
</property>
</bean>
<!-- 开启缓存注解 -->
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg index="0" ref="redisTemplate" />
<property name="expires">
<map>
<entry key="user" value="600" />
<entry key="city" value="6000" />
</map>
</property>
</bean>
</beans>
运行后可以用RedisDesktopManager登录看到这两个key的TTL不一样一个是600s,一个是6000s