Spring Boot整合Redis


Spring Boot整合Redis

spring boot提供了spring-data-redis庫來整合 Redis的操作,並通過簡單的配置信息實現與Redis的整合。

PS:個人還是習慣於使用 Jedis 面向 Java 客戶端操作 Redis

廢話不多說,上代碼。 😃

  • Maven 依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Spring Boot項目里不用加版本號,加入 spring-boot-starter-data-redis 即可 -->
<!-- 非Spring Boot項目下,可在 maven repository 中選合適的版本號 -->
<!-- 面向java客戶端Redis操作 -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
  • Jedis配置
########################## redis ###################################
# Redis服務器地址
spring.redis.host=127.0.0.1
# Redis服務器連接密碼(默認為空)
spring.redis.password=123456
# Redis服務器連接端口
spring.redis.port=6379
# 連接超時時間(毫秒)
spring.redis.timeout=3000
# redis 連接池配置
# 池中最大鏈接數
spring.redis.pool-config.max-total=256
# 連接池中的最大空閑連接
spring.redis.pool-config.max-idle=3000
# 連接池中的最小空閑連接
spring.redis.pool-config.min-idle=8
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool-config.max-wait-millis=1000
# 調用者獲取鏈接時,是否檢測當前鏈接有效性
spring.redis.pool-config.test-on-borrow=false
# 向鏈接池中歸還鏈接時,是否檢測鏈接有效性
spring.redis.pool-config.test-on-return=false
# 調用者獲取鏈接時,是否檢測空閑超時, 如果超時,則會被移除
spring.redis.pool-config.test-while-idle=true
# 空閑鏈接檢測線程一次運行檢測多少條鏈接
spring.redis.pool-config.num-tests-per-eviction-run=8
# 空閑鏈接檢測線程檢測周期。如果為負值,表示不運行檢測線程。(單位:毫秒,默認為-layer)
spring.redis.pool-config.time-between-eviction-runs-millis=60000
# 配置一個連接在池中最小生存的時間,單位是毫秒
spring.redis.pool-config.min-evictable-idle-time-millis=300000

注:properties中的配置可根據項目實際情況自己調整,我不敢保證以上配置所有項目都適用

  • 封裝Properties Redis配置
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

    private String host;

    private String password;

    private int port;

    private int timeout;
	
    // 此對象的句柄命名要和 Properties 中一一對應
    // Properties 中為 “pool-config” 那么這里應為 “poolConfig”
    private RedisPoolConfigProperties poolConfig = new RedisPoolConfigProperties();

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public RedisPoolConfigProperties getPoolConfig() {
        return poolConfig;
    }

    public void setPoolConfig(RedisPoolConfigProperties poolConfig) {
        this.poolConfig = poolConfig;
    }

    @Override
    public String toString() {
        return "RedisProperties{" +
                "host='" + host + '\'' +
                ", password='" + password + '\'' +
                ", port=" + port +
                ", timeout=" + timeout +
                ", poolConfig=" + poolConfig +
                '}';
    }
}
// 該對象為 上面 RedisProperties 中的一個屬性
public class RedisPoolConfigProperties {

    private int maxTotal;

    private int maxIdle;

    private int minIdle;

    private int maxWaitMillis;

    private Boolean testOnBorrow;

    private Boolean testOnReturn;

    private Boolean testWhileIdle;

    private int numTestsPerEvictionRun;

    private int timeBetweenEvictionRunsMillis;

    private int minEvictableIdleTimeMillis;

    public int getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMinIdle() {
        return minIdle;
    }

    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    public int getMaxWaitMillis() {
        return maxWaitMillis;
    }

    public void setMaxWaitMillis(int maxWaitMillis) {
        this.maxWaitMillis = maxWaitMillis;
    }

    public Boolean getTestOnBorrow() {
        return testOnBorrow;
    }

    public void setTestOnBorrow(Boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    public Boolean getTestOnReturn() {
        return testOnReturn;
    }

    public void setTestOnReturn(Boolean testOnReturn) {
        this.testOnReturn = testOnReturn;
    }

    public Boolean getTestWhileIdle() {
        return testWhileIdle;
    }

    public void setTestWhileIdle(Boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }

    public int getNumTestsPerEvictionRun() {
        return numTestsPerEvictionRun;
    }

    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
    }

    public int getTimeBetweenEvictionRunsMillis() {
        return timeBetweenEvictionRunsMillis;
    }

    public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }

    public int getMinEvictableIdleTimeMillis() {
        return minEvictableIdleTimeMillis;
    }

    public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }

    @Override
    public String toString() {
        return "RedisPoolConfigProperties{" +
                "maxTotal=" + maxTotal +
                ", maxIdle=" + maxIdle +
                ", minIdle=" + minIdle +
                ", maxWaitMillis=" + maxWaitMillis +
                ", testOnBorrow=" + testOnBorrow +
                ", testOnReturn=" + testOnReturn +
                ", testWhileIdle=" + testWhileIdle +
                ", numTestsPerEvictionRun=" + numTestsPerEvictionRun +
                ", timeBetweenEvictionRunsMillis=" + timeBetweenEvictionRunsMillis +
                ", minEvictableIdleTimeMillis=" + minEvictableIdleTimeMillis +
                '}';
    }
}

注:封裝對象時一定要注意,在Properties中的每個屬性對應在JavaBean中要一一對應,並使用駝峰是命名。

max-total 對應 Java Bean 屬性為 maxTotal;password 對應 Java Bean 屬性為 password

  • Redis配置納入JedsiPool(Jedis連接池)中,並把JedsiPool交由Spring管理
@Configuration
public class RedisConfig {

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

	// 此處通過構造方法注入了 RedisProperties 
    // 也可改成:
    // @Autowired 
    // private RedisProperties redis;
    private final RedisProperties redis;
    public RedisConfig(RedisProperties redis) {
        this.redis = redis;
    }

    @Bean
    public JedisPool jedisPool() {
        RedisPoolConfigProperties poolConfig = redis.getPoolConfig();
        final JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(poolConfig.getMaxTotal());
        jedisPoolConfig.setMaxIdle(poolConfig.getMaxIdle());
        jedisPoolConfig.setMaxWaitMillis(poolConfig.getMaxWaitMillis());
        jedisPoolConfig.setMinIdle(poolConfig.getMinIdle());
        jedisPoolConfig.setMinEvictableIdleTimeMillis(poolConfig.getMinEvictableIdleTimeMillis());
        jedisPoolConfig.setNumTestsPerEvictionRun(poolConfig.getNumTestsPerEvictionRun());
        jedisPoolConfig.setTestOnBorrow(poolConfig.getTestOnBorrow());
        jedisPoolConfig.setTestOnReturn(poolConfig.getTestOnReturn());
        jedisPoolConfig.setTestWhileIdle(poolConfig.getTestWhileIdle());
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(poolConfig.getTimeBetweenEvictionRunsMillis());
        log.info("JedisPoolConfig Initialize ........");
        log.info("JedisPoolConfig Info ........ {}", poolConfig);
        String host = redis.getHost();
        String password = redis.getPassword();
        int port = redis.getPort();
        int timeout = redis.getTimeout();
        final JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);
        log.info("JedisPool Initialize ........");
        log.info("redis address---> {}:{}", host, port);
        return jedisPool;
    }
}

至此,JedisPool已經納入了Spring中,如果中間有錯誤,細心檢查一下。 😃

  • 封裝操作 Jedis 接口
public interface JedisClient {

    /**
     * 將字符串值 value 關聯到 key
     */
    void set(String key, String value);

    /**
     * 返回 key 所關聯的字符串值。
     * 如果 key 不存在那么返回特殊值 nil 。
     * 假如 key 儲存的值不是字符串類型,返回一個錯誤,因為 GET 只能用於處理字符串值。
     */
    String get(String key);

    /**
     * 檢查給定 key 是否存在。
     */
    Boolean exists(String key);

    /**
     * 為給定 key 設置生存時間,當 key 過期時(生存時間為 0 ),它會被自動刪除。
     * 單位:秒
     */
    void expire(String key, int seconds);

    /**
     * 以秒為單位,返回給定 key 的剩余生存時間(TTL, time to live)。
     */
    Long ttl(String key);

    /**
     * 將 key 中儲存的數字值增一。
     * 如果 key 不存在,那么 key 的值會先被初始化為 0 ,然后再執行 INCR 操作。
     */
    Long incr(String key);

    /**
     * 將 key 中儲存的數字值減一。
     * 如果 key 不存在,那么 key 的值會先被初始化為 0 ,然后再執行 DECR 操作。
     * 如果值包含錯誤的類型,或字符串類型的值不能表示為數字,那么返回一個錯誤。
     */
    Long decr(String key);

    /**
     * 將哈希表 key 中的域 field 的值設為 value 。
     * 如果 key 不存在,一個新的哈希表被創建並進行 HSET 操作。
     * 如果域 field 已經存在於哈希表中,舊值將被覆蓋。
     */
    Long hset(String key, String field, String value);

    /**
     * 返回哈希表 key 中給定域 field 的值。
     */
    String hget(String key, String field);

    /**
     * 刪除哈希表 key 中的一個或多個指定域,不存在的域將被忽略。
     */
    Long hdel(String key, String... field);

    /**
     * 查看哈希表 key 中,給定域 field 是否存在。
     */
    Boolean hexists(String key, String field);

    /**
     * 返回哈希表 key 中所有域的值。
     */
    List<String> hvals(String key);

    /**
     * 刪除給定的一個 key 。
     */
    Long del(String key);

    /**
     * 存儲數據到緩存中,並制定過期時間和當Key存在時是否覆蓋。
     * @param nxxx 值只能取NX或者XX,如果取NX,則只有當key不存在是才進行set,如果取XX,則只有當key已經存在時才進行set
     * @param expx expx的值只能取EX或者PX,代表數據過期時間的單位,EX代表秒,PX代表毫秒。
     * @param time 過期時間,單位是expx所代表的單位。
     */
    String set(String key, String value, String nxxx, String expx, long time);

    /**
     * redis 腳本擴展器
     */
    Object eval(String script, List<String> keys, List<String> args);

    /**
     * 將值 value 關聯到 key ,並將 key 的生存時間設為 seconds (以秒為單位)。
     * 如果 key 已經存在, SETEX 命令將覆寫舊值。
     * 原子性(atomic)操作,關聯值和設置生存時間兩個動作會在同一時間內完成
     * @param seconds 以秒為單位
     */
    boolean setex(String key, String value, int seconds);

    /**
     * 訂閱一個或多個符合給定模式的頻道。
     * 每個模式以 * 作為匹配符,比如 it* 匹配所有以 it 開頭的頻道( it.news 、 it.blog 、 it.tweets 等等),
     * news.* 匹配所有以 news. 開頭的頻道( news.it 、 news.global.today 等等),諸如此類。
     */
    <T extends JedisPubSub> void psubscribe(T jedisPubSub, String... patterns);
}
  • 對應實現
/**
 * Redis實現
 */
@Configuration
public class JedisClientPool implements JedisClient {

    private final JedisPool jedisPool;

    private static final Logger logger = LoggerFactory.getLogger(JedisClientPool.class);

    @Autowired
    public JedisClientPool(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }

    @Override
    public void set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        jedis.set(key, value);
        jedis.close();
    }

    @Override
    public String get(String key) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.get(key);
        jedis.close();
        return result;
    }

    @Override
    public Boolean exists(String key) {
        Jedis jedis = jedisPool.getResource();
        Boolean result = jedis.exists(key);
        jedis.close();
        return result;
    }

    @Override
    public void expire(String key, int seconds) {
        Jedis jedis = jedisPool.getResource();
        jedis.expire(key, seconds);
        jedis.close();
    }

    @Override
    public Long ttl(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.ttl(key);
        jedis.close();
        return result;
    }

    @Override
    public Long incr(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.incr(key);
        jedis.close();
        return result;
    }

    @Override
    public Long decr(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.decr(key);
        jedis.close();
        return result;
    }

    @Override
    public Long hset(String key, String field, String value) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hset(key, field, value);
        jedis.close();
        return result;
    }

    @Override
    public String hget(String key, String field) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.hget(key, field);
        jedis.close();
        return result;
    }

    @Override
    public Long hdel(String key, String... field) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hdel(key, field);
        jedis.close();
        return result;
    }

    @Override
    public Boolean hexists(String key, String field) {
        Jedis jedis = jedisPool.getResource();
        Boolean result = jedis.hexists(key, field);
        jedis.close();
        return result;
    }

    @Override
    public List<String> hvals(String key) {
        Jedis jedis = jedisPool.getResource();
        List<String> result = jedis.hvals(key);
        jedis.close();
        return result;
    }

    @Override
    public Long del(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.del(key);
        jedis.close();
        return result;
    }

    @Override
    public String set(String key, String value, String nxxx, String expx, long time) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(key, value, nxxx, expx, time);
        jedis.close();
        return result;
    }

    @Override
    public Object eval(String script, List<String> keys, List<String> args) {
        Jedis jedis = jedisPool.getResource();
        Object result = jedis.eval(script, keys, args);
        jedis.close();
        return result;
    }

    @Override
    public boolean setex(String key, String value, int seconds) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.setex(key, seconds, value);
        jedis.close();
        return "ok".equalsIgnoreCase(result);
    }

    @Override
    public <T extends JedisPubSub> void psubscribe(T jedisPubSub, String... patterns) {
        Jedis jedis = jedisPool.getResource();
        String parameter = "notify-keyspace-events";
        List<String> notify = jedis.configGet(parameter);
        if(StringUtils.isBlank(notify.get(1))) {
            logger.info("重新設置過期事件 -->"+parameter);
            // 過期事件
            jedis.configSet(parameter, "Ex"); 
        }
        jedis.psubscribe(jedisPubSub, patterns);
        jedis.close();
    }
}

至此,所有流程OK,測試一下~

  • 單元測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class ZjH5ApplicationTests {
	
	@Autowired
	private JedisClient jedis;
	
	@Test
	public void contextLoads() {
		jedis.set("test..........", String.valueOf(System.currentTimeMillis()));
	}

}

在這里插入圖片描述

測試OK,可以開心的擼代碼啦~~~

注:如果流程中出現什么問題記得耐心的查看日志。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM