Redis与Spring集成:详解系列教程

发表时间: 2020-02-18 16:24

本章我们将实例讲解Redis如何与Spring整合。由于Redis与Spring的整合手段比较多,本章将着重讲解Spring与Spring-data-redis整合。

实例

新建Maven web项目,并将指定build path source folder。

项目结构

  • Customize build path source folder。

  • 文件代码
  • pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sstps.oscar</groupId>
    <artifactId>Template2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!-- Hack:确保commons-logging的jar包不被引入,否则将和jcl-over-slf4j冲突 -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>


  • redis.properties
redis.host=127.0.0.1
redis.port=6379
redis.pass=wljr
redis.timeout=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true


  • AplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <context:property-placeholder location="classpath:redis.properties" />
    <context:component-scan base-package="com.x.redis.dao">
    </context:component-scan>
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxActive" value="${redis.maxActive}" />
        <property name="maxWait" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    <bean id="connectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}"></property>
        <property name="port" value="${redis.port}"></property>
        <property name="password" value="${redis.pass}"></property>
        <property name="timeout" value="${redis.timeout}"></property>
    </bean>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
    </bean>
    <bean id="userDAO" class="com.x.redis.dao.imp.UserDAOImpl" />
</beans>


  • UserDao.java
package com.x.redis.dao;
import com.x.redis.pojo.User;
public interface UserDao {
    public void saveUser(final User user);
     public User getUser(final long id);
}


  • User.java
package com.x.redis.pojo;
public class User {
    private long id;
    private String name;
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}


  • UserDaoImpl.java
package com.x.redis.dao.imp;
import java.io.Serializable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import com.x.redis.dao.UserDao;
import com.x.redis.pojo.User;
public class UserDAOImpl implements UserDao {
        public void saveUser(final User user) {
            redisTemplate.execute(new RedisCallback<Object>() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    connection.set(redisTemplate.getStringSerializer().serialize("user.uid." + user.getId()),
                                   redisTemplate.getStringSerializer().serialize(user.getName()));
                    return null;
                }
            });
        }
        @Override
        public User getUser(final long id) {
            return redisTemplate.execute(new RedisCallback<User>() {
                @Override
                public User doInRedis(RedisConnection connection) throws DataAccessException {
                    byte[] key = redisTemplate.getStringSerializer().serialize("user.uid." + id);
                    if (connection.exists(key)) {
                        byte[] value = connection.get(key);
                        String name = redisTemplate.getStringSerializer().deserialize(value);
                        User user = new User();
                        user.setName(name);
                        user.setId(id);
                        return user;
                    }
                    return null;
                }
            });
        }
}
  • Template.java
package com.x.redis.template;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.x.redis.dao.imp.UserDAOImpl;
import com.x.redis.pojo.User;
public class Temolate {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/AplicationContex.xml");
        UserDAOImpl userDAOImpl = (UserDAOImpl) ac.getBean("userDAO");
        User user1 = new User();
        user1.setId(1);
        user1.setName("Hi~Redis");
        userDAOImpl.saveUser(user1);
        User user2 = userDAOImpl.getUser(1);
        System.out.println(user2.getName());
    }
}


运行结果:

总结

总的来说Spring+Spring-data-redis整合算是一种比较官方比较主流的方式,下面我们总结一下Spring+Spring-data-redis整合的优缺点:

  • 缺点

对Jedispool的封装过于完美以至于当完美需要灵活使用jedispool的时候无法自定义。

RedisCliTemplate想对较复杂,而且每次要获得RedisClientTemplate有需要RedisConnection的协助,这点在UserDaoImpl.java的两个方法中提现地尤为突出。

…..

  • 优点

配置优雅,封装集成度高。

….

Redis 讲解系列之 与Spring集成(二)

上章中我们讲解了如何使用spring与spring-data-redis如何整合在一起同时总结出了一些优缺点,正对于缺点的优化和改善,本章将讲解一种高自定获取Jedispool和RedisClientTemplate的方法。

实例

新建Maven web项目,并自定义Build path source folde。

文件代码

  • pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sstps.redis</groupId>
    <artifactId>Template1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.1.2.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>3.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.4.2</version>
        </dependency>
        <!-- Hack:确保commons-logging的jar包不被引入,否则将和jcl-over-slf4j冲突 -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
  • redis.properties
# Redis settings
redis.host=127.0.0.1
redis.port=6379
redis.password=wljr
redis.timeout=3000
redis.maxIdle=300
redis.maxTotal=600
redis.maxWait=1000
redis.testOnBorrow=true
redis.testOnReturn=true
  • AplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<!-- 启用注解 -->
<context:annotation-config></context:annotation-config>
<!-- 扫描 -->
<context:component-scan base-package="com.sstps.redis" use-default-filters="true"></context:component-scan>
<!-- 读取配置文件 -->
<bean id="propertyConfiguration" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>/WEB-INF/classes/redis.properties</value>
        </list>
    </property>
</bean>
<!-- ==================================   Redis 配置开始       ================================================= -->
<!-- Redis Template -->
<bean id="" class="com.sstps.redis.RedisClientTemplate">
    <property name="redisDataSource" ref="redisDataSource"></property>
</bean>
<!-- Redis DataSource -->
<bean id="redisDataSource" class="com.sstps.redis.RedisDataSourceImpl">
    <property name="jedisPool" ref="jedispool"></property>
</bean>
<!-- Redis pool setting -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="${redis.maxIdle}"></property>  
    <property name="maxTotal" value="${redis.maxTotal}"></property>
    <property name="maxWaitMillis" value="${redis.maxWait}"></property>
    <property name="testOnBorrow" value="${redis.testOnBorrow}"></property>
    <property name="testOnReturn" value="${redis.testOnReturn}"></property>
</bean>
<!-- Redis Connector setting -->
<bean id="jedispool" class="redis.clients.jedis.JedisPool">
     <constructor-arg index="0" ref="jedisPoolConfig"/>
      <constructor-arg index="1" value="${redis.host}"/>
      <constructor-arg index="2" value="${redis.port}" type="int"/>
      <constructor-arg index="3" value="${redis.timeout}" type="int"/>
      <constructor-arg index="4" value="${redis.password}"/>
</bean>
<!-- ==================================   Redis 配置结束       ================================================= -->
</beans>
  • RedisDataSource.java
  1. package com.sstps.redis;
  2. import redis.clients.jedis.Jedis;
  3. public interface RedisDataSource {
  4. // 取得redis的客户端,可以执行命令了。
  5. public abstract Jedis getRedisClient();
  6. //将资源返还给pool
  7. public void returnResource(Jedis shardedJedis);
  8. //出现异常后,将资源返还给pool
  9. public void returnResource(Jedis shardedJedis,boolean broken);
  10. }
  • RedisDataSourceImpl.java
  1. package com.sstps.redis;
  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;
  4. import redis.clients.jedis.Jedis;
  5. import redis.clients.jedis.JedisPool;
  6. public class RedisDataSourceImpl implements RedisDataSource {
  7. public static Log log = LogFactory.getLog(RedisDataSourceImpl.class);
  8. private JedisPool jedisPool;
  9. public JedisPool getJedisPool() {
  10. return jedisPool;
  11. }
  12. public void setJedisPool(JedisPool JedisPool) {
  13. this.jedisPool = JedisPool;
  14. }
  15. public Jedis getRedisClient() {
  16. try {
  17. Jedis shardJedis = jedisPool.getResource();
  18. return shardJedis;
  19. } catch (Exception e) {
  20. log.error("getRedisClent error", e);
  21. }
  22. return null;
  23. }
  24. public void returnResource(Jedis Jedis) {
  25. jedisPool.returnResource(Jedis);
  26. }
  27. public void returnResource(Jedis Jedis, boolean broken) {
  28. if (broken) {
  29. jedisPool.returnBrokenResource(Jedis);
  30. } else {
  31. jedisPool.returnResource(Jedis);
  32. }
  33. }
  34. }
  • Template.java
  1. package com.sstps.template;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. import com.sstps.redis.RedisClientTemplate;
  5. public class Template {
  6. public static void main(String[] args) {
  7. ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/AplicationContext.xml");
  8. RedisClientTemplate redisClient = (RedisClientTemplate)ac.getBean("redisClientTemplate");
  9. redisClient.set("a", "Hi~Redis");
  10. System.out.println(redisClient.get("a"));
  11. }
  12. }
  • RedisClientTemplate.java

总结

Redis与Spring直接整合,而对RedisClientTemplate和JedisPool做了剥离和二次封装。下面我们总结一下本章方法的优缺点:

缺点

代码较冗余,毕竟是二次封装,从RedisClientTemplate.java即可看出。

…..

-

优点

使用体验极好,不要考虑考虑新建或者归还jedispool的问题。使用时直接使用RedisClientTemplate即可。

优化点

考虑将本章例子的Redis打成jar包已依赖的方式导入,然后在AplictionContext.xml完成同样的配置,这样依赖代码既不冗余,灵活性和实用性极高了。