【Spring Boot学习总结】14.Spring Boot整合Redis-与传统方式对比

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013517797/article/details/83035604

前面我们讲解了如何使用Spring Boot来控制事务,下面我们来讲解一下如何使用Spring Boot来整合Redis
为了对比传统工程与Spring Boot整合的不同,以及彰显Spring Boot整合的优势,我们会逐一剖析传统整合方式与Spring Boot整合方式。

一、传统方式整合Redis

在不使用Spring Boot的传统工程中,我们使用XML配置文件来整合Redis。首先在POM文件中引入Redis的相关依赖:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.6.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.7.3</version>
</dependency>

然后创建一个redis.properties文件,用于配置redis的连接信息:

# Redis服务器地址
redis.host=127.0.0.1
# Redis服务器连接端口
redis.port=6379  
# Redis服务器连接密码(默认为空)
redis.pass=password
redis.dbIndex=0  
# Redis中Key的过期时间
redis.expiration=3000  
# 连接池中的最大空闲连接
redis.maxIdle=300  
# 连接池最大连接数(使用负值表示没有限制)
redis.maxActive=600  
# 连接池最大阻塞等待时间(使用负值表示没有限制)
redis.maxWait=1000  
redis.testOnBorrow=true

然后在Spring的配置文件中(含有数据源、sessionFactory等Bean配置的文件),添加Redis的配置:

<!-- redis config start -->
<!-- 配置JedisPoolConfig实例 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="${redis.maxIdle}" />
    <property name="maxTotal" value="${redis.maxActive}" />
    <property name="maxWaitMillis" value="${redis.maxWait}" />
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>

<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="${redis.host}" />
    <property name="port" value="${redis.port}" />
    <property name="password" value="${redis.pass}" />
    <property name="database" value="${redis.dbIndex}" />
    <property name="poolConfig" ref="poolConfig" />
</bean>

<!-- 配置RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>

<!-- 配置RedisCacheManager -->
<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
    <constructor-arg name="redisOperations" ref="redisTemplate" />
    <property name="defaultExpiration" value="${redis.expiration}" />
</bean>

<!-- 配置RedisCacheConfig -->
<bean id="redisCacheConfig" class="com.ssm.utils.RedisCacheConfig">
    <constructor-arg ref="jedisConnectionFactory" />
    <constructor-arg ref="redisTemplate" />
    <constructor-arg ref="redisCacheManager" />
</bean>
<!-- redis config end -->

其中分别配置了JedisPoolConfig、JedisConnectionFactory、RedisTemplate、RedisCacheManager、RedisCacheConfig,其中:
(1)JedisPoolConfig
JedisPoolConfig类中设置了redis连接池的配置信息,用于通过配置信息来控制redis数据库连接池的一些连接操作。

(2)JedisConnectionFactory
JedisConnectionFactory类为redis数据库的连接工厂类,类似引入了DataSource的SqlSessionFactory数据库会话工厂。
该类通过配置的redis数据库的连接信息,来与redis数据库进行连接操作,并返回相应的连接实例对象。

(3)RedisTemplate
RedisTemplate类是redis操作类,通过引入JedisConnectionFactory连接工厂获取连接,对外提供redis的各种操作API,
在项目中可以直接使用RedisTemplate类来进行redis数据库的操作。

(4)RedisCacheManager
RedisCacheManager为redis自定义的工具类,在构造方法中引入了RedisTemplate,旨在对redis数据库中的key-value数据进行管理,例如设置了key的失效时间等。

(5)RedisCacheConfig
RedisCacheConfig类是需要开发者自定义的类,用于为redis做统一的调度和管理。该类需继承CachingConfigurerSupport父类,分别注入了JedisConnectionFactory、RedisTemplate以及RedisCacheManager。
下面是一个自定义RedisCacheConfig:

package com.ssm.utils;
import java.lang.reflect.Method;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 通过spring管理redis缓存配置
 * @author Administrator
 */
@Configuration  
@EnableCaching 
public class RedisCacheConfig extends CachingConfigurerSupport {
    private volatile JedisConnectionFactory jedisConnectionFactory;
    private volatile RedisTemplate<String, String> redisTemplate;
    private volatile RedisCacheManager redisCacheManager;

    public RedisCacheConfig() {
        super();
    }

    /**
     * 带参数的构造方法 初始化所有的成员变量
     * 
     * @param jedisConnectionFactory
     * @param redisTemplate
     * @param redisCacheManager
     */
    public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, String> redisTemplate,
            RedisCacheManager redisCacheManager) {
        this.jedisConnectionFactory = jedisConnectionFactory;
        this.redisTemplate = redisTemplate;
        this.redisCacheManager = redisCacheManager;
    }

    public JedisConnectionFactory getJedisConnecionFactory() {
        return jedisConnectionFactory;
    }

    public RedisTemplate<String, String> getRedisTemplate() {
        return redisTemplate;
    }

    public RedisCacheManager getRedisCacheManager() {
        return redisCacheManager;
    }

    @Bean
    public KeyGenerator customKeyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... objects) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : objects) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }
}

该类继承CachingConfigurerSupport,用于手动修改redis相关设置。这里重写customKeyGenerator方法,提供了key的默认生成方式(类名+方法名)。下面就是在我们的Service中使用缓存,有两种方式,第一种就是开发一个工具类xxxRedisUtils,将RedisTemplate类注入进该类,然后提供各种操作,如下类:

@Service
public class RedisCacheUtil<T>{

     @Autowired @Qualifier("jedisTemplate")
     public RedisTemplate redisTemplate;

     /**
      * 缓存基本的对象,Integer、String、实体类等
      * @param key 缓存的键值
      * @param value 缓存的值
      * @return  缓存的对象
      */
     public <T> ValueOperations<String,T> setCacheObject(String key,T value){
          ValueOperations<String,T> operation = redisTemplate.opsForValue(); 
          operation.set(key,value);
          return operation;
     }
     
     //其它各种操作省略...
}

然后在Service中注入RedisCacheUtil类进行缓存的操作即可:

@Autowired
private RedisCacheUtil<User> redisCache;

第二种就是在Service直接使用注解的方式来进行缓存的操作,这种也是比较方便的方式:
有两种常用注解,分别是@Cacheable和@CacheEvict,用于缓存的设置和清理:
(1)@Cacheable("a")
该注解的意义就是把该方法的查询结果放到redis中去,下一次再发起查询就去redis中去取,存在redis中的数据的key就是a;
(2)@CacheEvict(value={"a","b"},allEntries=true) 
该注解的意思就是执行该方法后要清除redis中key名称为a,b的数据;使用样例:

@Cacheable("getUserById")//标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
@Override
public User getUserById(int userId) {
    return this.iUserDao.selectByPrimaryKey(userId);
}

@CacheEvict(value= {"getAllUser","getUserById","findUsers"},allEntries=true)//清空缓存,allEntries变量表示所有对象的缓存都清除
@Override
public void insertUser(User user) {
    this.iUserDao.insertUser(user);
}

以上就是使用传统方式整合redis的操作方式。可以看出配置步骤还是比较繁琐的。


二、使用Spring Boot整合Redis原理剖析

说白了,Spring Boot针对Redis的整合,有一部分依赖了Spring Boot的自动配置机制。
我们先来了解一下Spring Boot针对Spring Boot的自动化配置原理:
一般我们在使用Spring Boot的时候要编写一个启动类:

package cn.com.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//Sprnig Boot项目的核心注解,主要目的是开启自动配置
public class MainApplication {
    //该main方法作为项目启动的入口
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

因为Spring Boot可以开启自动配置(@SpringBootApplication中的@EnableAutoConfiguration),SpringBootApplication对象实例化时会加载spring-boot的jar中的META-INF/spring.factories文件,
在该文件中设置了需要进行自动配置加载的实体类,其中就包含了redis的相关自动配置类:

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

其中RedisAutoConfiguration类会读取RedisProperties类中的参数作为配置项,而RedisProperties中的连接参数,是读取用户在properties中配置的,以“spring.redis”开头的配置项,通过源码可以看到:

package org.springframework.boot.autoconfigure.data.redis;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
    //内容源码省略...
}

RedisAutoConfiguration就是帮我们自动做了一些列的配置,我们在开发中只需要修改少量配置指向自己的redis服务地址即可。

那我们其实很清晰了,我们只需要在Spring Boot的properties文件中,使用“spring.redis”前缀进行redis连接信息的配置,就可以使用redis了!是不是很方便!

下面就是Spring Boot连整合redis的方式。

三、使用Spring Boot整合Redis步骤

首先在POM文件中引入redis的启动依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然后在修改项目启动类,增加注解@EnableCaching,开启缓存功能,如下:

package cn.com.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
//Sprnig Boot项目的核心注解,主要目的是开启自动配置
@EnableScheduling
@EnableCaching
public class MainApplication {
    //该main方法作为项目启动的入口
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

然后在application.properties中配置Redis连接信息,如下:

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=172.31.19.222
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

然后编写一个Redis缓存配置类RedisConfig,用于定义缓存key生成策略、缓存管理器、RedisTemplate等。如下:

package springboot.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;


/**
 * Redis缓存配置类
 * @author szekinwin
 *
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    
    //自定义缓存key生成策略
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator(){
            @Override
                public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
                    StringBuffer sb = new StringBuffer();
                    sb.append(target.getClass().getName());
                    sb.append(method.getName());
                    for(Object obj:params){
                        sb.append(obj.toString());
                    }
                    return sb.toString();
                }
            };
    }
    //缓存管理器
    @Bean 
    public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        //设置缓存过期时间 
        cacheManager.setDefaultExpiration(10000);
        return cacheManager;
    }
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
        StringRedisTemplate template = new StringRedisTemplate(factory);
        setSerializer(template);//设置序列化工具
        template.afterPropertiesSet();
        return template;
    }
     private void setSerializer(StringRedisTemplate template){
            @SuppressWarnings({ "rawtypes", "unchecked" })
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
            template.setValueSerializer(jackson2JsonRedisSerializer);
     }
}

然后在Service中使用redisTemplate或者直接使用@Cacheable和@CacheEvict来进行缓存操作即可。

当然你也可以像第一小节讲的那样,使用传统配置来进行redis的设置,不同的就是我们使用Java配置来代替XML配置,适合那些需要自己控制redis核心操作的项目。
使用Java方式配置,只需要新建一个类,然后使用@Configuration注解即可,然后使用配置的RedisTemplate类进行redis数据库的操作。这里不再赘述。

四、补充:redis集群操作

上面讲的都是针对redis单机版进行的操作,而目前我们的企业级项目都是搭建了redis集群来进行redis管理的,这里我们来补充一下传统模式和Spring Boot模式对
redis集群的操作。

(1)传统方式操作redis集群
修改redis.propertis,放置集群配置:

redis.host1=192.168.1.235
redis.port1=7001
redis.host2=192.168.1.235
redis.port2=7002
redis.host3=192.168.1.235
redis.port3=7003
redis.host4=192.168.1.235
redis.port4=7004
redis.host5=192.168.1.235
redis.port5=7005
redis.host6=192.168.1.235
redis.port6=7006
 
redis.maxRedirects=3
redis.maxIdle=30
redis.maxTotal=100
redis.minIdle=5
redis.maxWaitMillis=30000 
redis.testOnBorrow=true
redis.testOnReturn=true 
redis.testWhileIdle=true
redis.timeout=3000

然后在spring配置文件中,配置RedisClusterConfiguration类,将集群信息放置进去:

<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">  
                <property name="maxRedirects" value="${redis.maxRedirects}"></property>  
            <property name="clusterNodes">  
                <set>  
                    <bean class="org.springframework.data.redis.connection.RedisNode">  
                        <constructor-arg name="host" value="${redis.host1}"></constructor-arg>  
                        <constructor-arg name="port" value="${redis.port1}"></constructor-arg>  
                    </bean>  
                    <bean class="org.springframework.data.redis.connection.RedisNode">  
                        <constructor-arg name="host" value="${redis.host2}"></constructor-arg>  
                        <constructor-arg name="port" value="${redis.port2}"></constructor-arg>  
                    </bean>  
                    <bean class="org.springframework.data.redis.connection.RedisNode">  
                        <constructor-arg name="host" value="${redis.host3}"></constructor-arg>  
                        <constructor-arg name="port" value="${redis.port3}"></constructor-arg>  
                    </bean>  
                    <bean class="org.springframework.data.redis.connection.RedisNode">  
                        <constructor-arg name="host" value="${redis.host4}"></constructor-arg>  
                        <constructor-arg name="port" value="${redis.port4}"></constructor-arg>  
                    </bean>  
                    <bean class="org.springframework.data.redis.connection.RedisNode">  
                        <constructor-arg name="host" value="${redis.host5}"></constructor-arg>  
                        <constructor-arg name="port" value="${redis.port5}"></constructor-arg>  
                    </bean>  
                    <bean class="org.springframework.data.redis.connection.RedisNode">  
                        <constructor-arg name="host" value="${redis.host6}"></constructor-arg>  
                        <constructor-arg name="port" value="${redis.port6}"></constructor-arg>  
                    </bean>  
            </set>  
    </property>  
</bean> 

然后将配置好的RedisClusterConfiguration作为参数,引入到之前配置好的jeidsConnectionFactory中即可:

<bean id="jeidsConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  >  
    <property name="poolConfig" ref="jedisPoolConfig" />
    <constructor-arg name="clusterConfig" ref="redisClusterConfiguration"/>  
    <constructor-arg name="poolConfig" ref="jedisPoolConfig"/>   
</bean> 

其它配置就无需修改(redisTemplate等配置),在后面使用redis的操作也类似之前。

如果redis配置了主从,操作如下:
配置文件:

#sentinel1的IP和端口  
sentinel1.host=192.168.1.233
sentinel1.port=26379  
#sentinel2的IP和端口  
sentinel2.host=192.168.1.233
sentinel2.port=26378 
 
im.hs.server.redis.maxIdle=500  
#最大连接数,超过此连接时操作redis会报错  
im.hs.server.redis.maxTotal=5000  
im.hs.server.redis.maxWaitTime=1000  
im.hs.server.redis.testOnBorrow=true  
#最小闲置连接数,spring启动的时候自动建立该数目的连接供应用程序使用,不够的时候会申请。  
im.hs.server.redis.minIdle=300
im.hs.server.redis.sentinel.masterName=mymaster

然后在XML配置文件中配置redisSentinelConfiguration类,将redis主从信息放入其中:

<bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <property name="master">
        <bean class="org.springframework.data.redis.connection.RedisNode">
            <property name="name" value="${im.hs.server.redis.sentinel.masterName}"/>
        </bean>
    </property>
    <property name="sentinels">
        <set>
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="${sentinel1.host}"></constructor-arg>
                <constructor-arg name="port" value="${sentinel1.port}"></constructor-arg>
            </bean>
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="${sentinel2.host}"></constructor-arg>
                <constructor-arg name="port" value="${sentinel2.port}"></constructor-arg>
            </bean>
        </set>
    </property>
</bean>
 
<bean id="jeidsConnectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration"></constructor-arg>  
    <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>      
</bean>

解释:sentinel意思是哨兵,用于监视主从服务器的运行状况,如果主服务器挂掉,会在从服务器中选举一个作为主服务器。 
其它配置就无需修改(redisTemplate等配置),在后面使用redis的操作也类似之前。

(2)Spring Boot操作redis集群
Spring Boot的集群配置就很简单了,修改原来的配置如下:

spring.redis.cluster.nodes=127.0.0.1:26379,127.0.0.1:26479,127.0.0.1:26579
spring.redis.password=password

余下的操作如之前。

主从配置:

# database name
spring.redis.database=0
# server host1 单机使用,对应服务器ip
#spring.redis.host=127.0.0.1  
# server password 密码,如果没有设置可不配
#spring.redis.password=
#connection port  单机使用,对应端口号
#spring.redis.port=6379
# pool settings ...池配置
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
# name of Redis server  哨兵监听的Redis server的名称
spring.redis.sentinel.master=mymaster
# comma-separated list of host:port pairs  哨兵的配置列表
spring.redis.sentinel.nodes=127.0.0.1:26379,127.0.0.1:26479,127.0.0.1:26579

以上就是Spring 以及Spring Boot针对redis的整合。


参考:
Spring集成redis:
https://www.cnblogs.com/hello-daocaoren/p/7891907.html
SpringBoot使用Redis缓存:
https://www.cnblogs.com/gdpuzxs/p/7222309.html
spring整合redis(集群、主从):
https://blog.csdn.net/sunqingzhong44/article/details/70976038?locationNum=6&fps=1
spring boot整合redis主从sentinel:
https://blog.csdn.net/liuchuanhong1/article/details/54601037

转载请注明出处:https://blog.csdn.net/acmman/article/details/83035604

猜你喜欢

转载自blog.csdn.net/u013517797/article/details/83035604
今日推荐