NoSQL Zone is brought to you in partnership with:

Highly motivated Senior Java/JEE Software Developer with 7+ years of solid industry experience. Excellent team player with an experience working in distributed international teams, using Agile/Scrum methodology. Artur has posted 9 posts at DZone. You can read more from them at their website. View Full User Profile

Spring Data & Redis

03.23.2012
| 10562 views |
  • submit to reddit

This article will cover the following topics:


  1. How to install Redis on a *nix machine.
  2. How to write a simple app using Spring-Data and Redis.

Before moving forward let's understand what Redis is.

Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.

In this article I'm not going to talk how fast is redis and how it works. But believe me it's a very fast key-value store.

Now let's install redis on *nix machine
wget http://redis.googlecode.com/files/redis-2.4.8.tar.gz
tar xzf redis-2.4.8.tar.gz
cd redis-2.4.8
make

src/redis-server

That's all! Your redis is ready to use.

Now let's create a simple maven application to work with redis.

 Currently Spring Redis has support for Jedis and JRedis (Jedis and JRedis are Redis bindings for Java).

 In this article we are going to use Jedis. Here are the Maven dependencies:

<!-- Redis Java Binding-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.0.0</version>
</dependency>

<!-- Spring Data Redis -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
     <version>1.0.0.RELEASE</version>
</dependency>

You can find the full application on GitHub here: spring-data-redis example

Now let's define and configure our beans:

<!-- redis conection factory -->
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:use-pool="true" p:host-name="${app.config.redis.host}" p:port="${app.config.redis.port}" p:password="${app.config.redis.password}"/>

<!-- redis template -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="connectionFactory"/>

<!-- redis string template -->
<bean id="redisStringTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"
p:connection-factory-ref="connectionFactory"/>

<!-- redis map binding -->
<bean id="userRedisMap" class="org.springframework.data.redis.support.collections.DefaultRedisMap">
    <constructor-arg ref="redisTemplate"/>
    <constructor-arg value="USER"/>
</bean>

RedisTemplate provides high level abstraction for redis operations. If your application stores and retrieves strings, then you may use StringRedisTemplate.

Let's create a simple domain object.

public interface Cachable extends Serializable {

    public String getKey();

    public String getObjectKey();
}

public class User implements Cachable {

    private static final long serialVersionUID = -7898194272883238670L;

    public static final String OBJECT_KEY = "USER";

    public User() {
    }

    public User(String id) {
    }

    public User(String id, String name) {
       this.id = id;
       this.name = name;
    }

    private String id;

    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + "]";
    }

    @Override
    public String getKey() {
        return getId();
    }

    @Override
    public String getObjectKey() {
        return OBJECT_KEY;
    }
}

Now let's create Service layer classes.

public interface Service<V extends Cachable> {

    public void put(V obj);

    public V get(V key);

    public void delete(V key);
}

@Service("userService")
public class UserService implements co.sdr.service.Service<User> {

    @Autowired
    RedisTemplate<String, Cachable> redisTemplate;

    @Override
    public void put(User user) {
        redisTemplate.opsForHash().put(user.getObjectKey(), user.getKey(), user);
    }

    @Override
    public void delete(User key) {
        redisTemplate.opsForHash().delete(key.getObjectKey(), key.getKey());
    }

    @Override
    public User get(User key) {
        return (User) redisTemplate.opsForHash().get(key.getObjectKey(), key.getKey());
    }
}

So domain and service classes are ready. Now let's use them.

Here is the simple Main class which uses the above-mentioned classes.

public class Main
{
    public static void main( String[] args )
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("springapp.xml");
    
        @SuppressWarnings("unchecked")
        Service<User> userService = (Service<User>)context.getBean("userService");
        
        User user1 = new User("user1ID", "User 1");
        User user2 = new User("user2ID", "User 2");
        
        System.out.println("==== getting objects from redis ====");
        System.out.println("User is not in redis yet: " + userService.get(user1));
        System.out.println("User is not in redis yet: " + userService.get(user2));
        
        System.out.println("==== putting objects into redis ====");
        userService.put(user1);
        userService.put(user2);
        
        System.out.println("==== getting objects from redis ====");
        System.out.println("User should be in redis yet: " + userService.get(user1));
        System.out.println("User should be in redis yet: " + userService.get(user2));
        
        System.out.println("==== deleting objects from redis ====");
        userService.delete(user1);
        userService.delete(user2);
        
        System.out.println("==== getting objects from redis ====");
        System.out.println("User is not in redis yet: " + userService.get(user1));
        System.out.println("User is not in redis yet: " + userService.get(user2));

    }
}

Wasn't it simple? Spring makes everything much more easy to use.

And this isn't the end. spring-data-redis's org.springframework.data.redis.support package provides List, Set, Map implemetations.

Let's try to use a map:

@Service("userMapService")
public class UserMapService implements co.sdr.service.Service<User> {

    @Autowired
    Map<String, Cachable> userRedisMap;

    @Override
    public void put(User user) {
        userRedisMap.put(user.getKey(), user);
    }

   @Override
   public void delete(User key) {
       userRedisMap.remove(key.getKey());
   }

    @Override
    public User get(User key) {
        return (User) userRedisMap.get(key.getKey());
    }
}

This may help you with unit testing, and you may change the datastore without the changing service layer.

You may also use RedisCacheManager as a backing implementation for spring cache abstraction.

Find the full version of this application on GitHub here:  spring-data-redis example

Published at DZone with permission of its author, Artur Mkrtchyan.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)