Spring Boot integrates Redis

Spring Boot integrates Redis

spring boot provides the spring data Redis library to integrate Redis operations, and realizes the integration with Redis through simple configuration information.

PS: individuals are still used to using Jedis to operate Redis for Java clients

Don't talk too much, just code. : -)

  • Maven dependence
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<! -- in spring boot project, you don't need to add version number, just add spring boot starter data redis -- >
<! -- for non Spring Boot projects, select the appropriate version number in maven repository -- >
<! -- Redis operation for java client -- >
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
  • Jedis configuration
########################## redis ###################################
# Redis server address
spring.redis.host=127.0.0.1
# Redis server connection password (empty by default)
spring.redis.password=123456
# Redis server connection port
spring.redis.port=6379
# Connection timeout (MS)
spring.redis.timeout=3000
# redis connection pool configuration
# Maximum number of links in the pool
spring.redis.pool-config.max-total=256
# Maximum free connections in connection pool
spring.redis.pool-config.max-idle=3000
# Minimum free connections in connection pool
spring.redis.pool-config.min-idle=8
# Connection pool maximum block wait time (use a negative value to indicate no limit)
spring.redis.pool-config.max-wait-millis=1000
# Whether to check the validity of the current link when the caller obtains the link
spring.redis.pool-config.test-on-borrow=false
# Check link validity when returning links to link pool
spring.redis.pool-config.test-on-return=false
# Whether to detect the idle timeout when the caller gets the link. If the timeout occurs, it will be removed
spring.redis.pool-config.test-while-idle=true
# How many links does idle link detection thread detect at a time
spring.redis.pool-config.num-tests-per-eviction-run=8
# Idle link detection thread detection cycle. If it is negative, the detection thread will not run. (unit: ms, default is - layer)
spring.redis.pool-config.time-between-eviction-runs-millis=60000
# Configure the minimum lifetime of a connection in the pool, in milliseconds
spring.redis.pool-config.min-evictable-idle-time-millis=300000

Note: the configuration in properties can be adjusted according to the actual situation of the project. I can't guarantee that all the above configuration items are applicable

  • Encapsulate Properties Redis configuration
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

    private String host;

    private String password;

    private int port;

    private int timeout;
    
    // The handle name of this object should correspond to Properties one by one
    // "Pool config" in Properties, then "poolConfig" should be used here "
    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 +
                '}';
    }
}
// This object is a property in RedisProperties above
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 +
                '}';
    }
}

Note: when encapsulating objects, it is important to note that each property in Properties corresponds to each other in JavaBean, and the hump is used for naming.

Max total corresponds to maxTotal in Java Bean attribute; password corresponds to password in Java Bean attribute

  • Bring Redis configuration into JedsiPool (Jedis connection pool) and leave it to Spring for management
@Configuration
public class RedisConfig {

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

    // Here, RedisProperties is injected through the construction method 
    // It can also be changed to:
    // @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;
    }
}

So far, JedisPool has been included in Spring. If there is any error in the middle, please check it carefully. : -)

  • Encapsulate operation Jedis interface
public interface JedisClient {

    /**
     * Associate string value to key
     */
    void set(String key, String value);

    /**
     * Returns the string value associated with the key.
     * If the key does not exist, the special value nil is returned.
     * If the value stored by key is not of string type, an error is returned, because GET can only be used to process string value.
     */
    String get(String key);

    /**
     * Check whether the given key exists.
     */
    Boolean exists(String key);

    /**
     * Set the lifetime for the given key. When the key expires (the lifetime is 0), it will be deleted automatically.
     * Unit: sec.
     */
    void expire(String key, int seconds);

    /**
     * Returns the TTL (time to live) of a given key in seconds.
     */
    Long ttl(String key);

    /**
     * Increase the number value stored in the key by one.
     * If the key does not exist, the value of the key is initialized to 0 before the INCR operation.
     */
    Long incr(String key);

    /**
     * Reduce the number value stored in the key by one.
     * If the key does not exist, the value of the key is initialized to 0 before DECR.
     * If the value contains the wrong type, or the value of string type cannot be represented as a number, an error is returned.
     */
    Long decr(String key);

    /**
     * Set the value of the field in the hash table key to value.
     * If the key does not exist, a new hash table is created and HSET is performed.
     * If the domain field already exists in the hash table, the old value will be overwritten.
     */
    Long hset(String key, String field, String value);

    /**
     * Returns the value of the given field in the hash table key.
     */
    String hget(String key, String field);

    /**
     * Delete one or more specified domains in the hash table key. Domains that do not exist will be ignored.
     */
    Long hdel(String key, String... field);

    /**
     * Check whether the given domain field exists in the hash table key.
     */
    Boolean hexists(String key, String field);

    /**
     * Returns the values of all fields in the hash table key.
     */
    List<String> hvals(String key);

    /**
     * Delete a given key.
     */
    Long del(String key);

    /**
     * Store the data in the cache, and determine the expiration time and whether to overwrite when the Key exists.
     * @param nxxx The value can only be NX or XX. If NX is selected, the value is set only when the key does not exist. If XX is selected, the value is set only when the key already exists
     * @param expx expx The value of can only take EX or Px, which represents the unit of data expiration time. EX represents seconds and PX represents milliseconds.
     * @param time Expiration time in the unit represented by expx.
     */
    String set(String key, String value, String nxxx, String expx, long time);

    /**
     * redis Script extender
     */
    Object eval(String script, List<String> keys, List<String> args);

    /**
     * Associate the value value to the key and set the key's lifetime to seconds.
     * If the key already exists, the SETEX command overwrites the old value.
     * Atomic operation, association value and set lifetime will be completed in the same time
     * @param seconds In seconds
     */
    boolean setex(String key, String value, int seconds);

    /**
     * Subscribe to one or more channels that match the given pattern.
     * Each pattern is matched by * for example, it * matches all channels that start with it (it.news, it.blog, it.tweets, etc.),
     * news.* Match all channels that start with news (news.it, news.global.today, and so on), and so on.
     */
    <T extends JedisPubSub> void psubscribe(T jedisPubSub, String... patterns);
}
  • Corresponding realization
/**
 * Redis Realization
 */
@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("Reset expiration events -->"+parameter);
            // Expired event
            jedis.configSet(parameter, "Ex"); 
        }
        jedis.psubscribe(jedisPubSub, patterns);
        jedis.close();
    }
}

So far, all the processes are OK. Test it~

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

}

Test OK, happy to roll up the code~~~

Note: if there is any problem in the process, please check the log patiently.

Keywords: Java Jedis Redis Spring

Added by CaptainStarbuck on Tue, 03 Dec 2019 14:55:32 +0200