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

这里写图片描述

互联网金融系列-支付清算体系例子-下(理解日切)

笔者上一篇《互联网金融系列-支付清算体系介绍-上》已经比较全面的介绍了以银联为例子的支付清算体系,为了更好的理解里面的运作,本章以两个例子为重点,全...

阅读全文

互联网金融系列-支付清算体系介绍-上

一,支付清算体系的简介 支付清算体系是一个国家的金融基础设施,或说公共服务。我国由央行主管此事,目前大体维持“结算-清算”二级制的支付体系。通俗地讲,...

阅读全文

JDK8 – 当尝试使用Maven生成javadoc时,错误“javax.interceptor.InterceptorBinding未找到的类文件”javadoc plugin

我使用JDK8(尝试它在我的Eclipse工作区与Win x64 u25 JDK在Linux上由Jenkins发布 – jdk-8u20-linux-x64,两个相同的问题)。我有多模块Maven项目(我从包装类...

阅读全文

欢迎留言