Статьи

Использование Redis с Spring

Поскольку решения NoSQL становятся все более популярными для решения многих видов проблем, современные проекты чаще используют некоторые (или несколько) NoSQL вместо (или бок о бок) традиционных СУБД. Я уже рассказал о своем опыте работы с MongoDB в этом , этом и этом постах. В этом посте я хотел бы немного переключиться на Redis , продвинутый магазин значений ключей.
Помимо очень богатой семантики ключ-значение, Redis также поддерживает обмен сообщениями и транзакции из публикации. В этой статье я просто коснусь поверхности и продемонстрирую, как просто интегрировать Redis в приложение Spring. Как всегда, мы начнем с файла POM Maven для нашего проекта:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  
  
 <modelversion>4.0.0</modelversion>
 <groupid>com.example.spring</groupid>
 <artifactid>redis</artifactid>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 
 <properties>
  <project.build.sourceencoding>UTF-8</project.build.sourceencoding>
  <spring.version>3.1.0.RELEASE</spring.version>
 </properties>
 
 <dependencies>
  <dependency>
   <groupid>org.springframework.data</groupid>
   <artifactid>spring-data-redis</artifactid>
   <version>1.0.0.RELEASE</version>
  </dependency>
 
  <dependency>
   <groupid>cglib</groupid>
   <artifactid>cglib-nodep</artifactid>
   <version>2.2</version>
  </dependency>
 
  <dependency>
   <groupid>log4j</groupid>
   <artifactid>log4j</artifactid>
   <version>1.2.16</version>
  </dependency>
 
  <dependency>
   <groupid>redis.clients</groupid>
   <artifactid>jedis</artifactid>
   <version>2.0.0</version>
   <type>jar</type>
  </dependency>
 
  <dependency>
   <groupid>org.springframework</groupid>
   <artifactid>spring-core</artifactid>
   <version>${spring.version}</version>
  </dependency>
 
  <dependency>
   <groupid>org.springframework</groupid>
   <artifactid>spring-context</artifactid>
   <version>${spring.version}</version>
  </dependency>
 </dependencies>
</project>
Spring Data Redis — это еще один проект под зонтиком Spring Data, который обеспечивает плавное внедрение Redis в ваше приложение. Существует несколько клиентов Redis для Java, и я выбрал Jedis, поскольку он стабилен и рекомендован командой Redis на момент написания этого поста.
Мы начнем с простой настройки и сначала представим необходимые компоненты. Затем, по мере продвижения вперед, конфигурация будет немного расширена, чтобы продемонстрировать возможности pub-sub. Благодаря поддержке конфигурации Java, мы создадим класс конфигурации и будем строго типизировать все наши зависимости, больше не будет XML:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.redis.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
 
@Configuration
public class AppConfig {
 @Bean
 JedisConnectionFactory jedisConnectionFactory() {
  return new JedisConnectionFactory();
 }
 
 @Bean
 RedisTemplate< String, Object > redisTemplate() {
  final RedisTemplate< String, Object > template =  new RedisTemplate< String, Object >();
  template.setConnectionFactory( jedisConnectionFactory() );
  template.setKeySerializer( new StringRedisSerializer() );
  template.setHashValueSerializer( new GenericToStringSerializer< Object >( Object.class ) );
  template.setValueSerializer( new GenericToStringSerializer< Object >( Object.class ) );
  return template;
 }
}
Это в основном все, что нам нужно, предполагая, что у нас есть один сервер Redis , работающий на локальном хосте с конфигурацией по умолчанию. Давайте рассмотрим несколько распространенных вариантов использования: установка ключа для некоторого значения, сохранение объекта и, наконец, реализация pub-sub. Хранить и извлекать пару ключ / значение очень просто:
1
2
3
4
5
6
7
8
9
@Autowired private RedisTemplate< String, Object > template;
 
public Object getValue( final String key ) {
    return template.opsForValue().get( key );
}
 
public void setValue( final String key, final String value ) {
    template.opsForValue().set( key, value );
}

При желании ключ может быть установлен на срок действия (еще одна полезная функция Redis ), например, срок действия ключей истекает через 1 секунду:

1
2
3
4
public void setValue( final String key, final String value ) {
    template.opsForValue().set( key, value );
    template.expire( key, 1, TimeUnit.SECONDS );
}

Произвольные объекты могут быть сохранены в Redis в виде хэшей (карт), например, можно сохранить экземпляр некоторого класса User

1
2
3
4
5
6
7
public class User {
 private final Long id;
 private String name;
 private String email;
        
    // Setters and getters are omitted for simplicity
}

в Redis, используя комбинацию клавиш «user: <id>» :

01
02
03
04
05
06
07
08
09
10
public void setUser( final User user ) {
 final String key = String.format( "user:%s", user.getId() );
 final Map< String, Object > properties = new HashMap< String, Object >();
 
 properties.put( "id", user.getId() );
 properties.put( "name", user.getName() );
 properties.put( "email", user.getEmail() );
 
 template.opsForHash().putAll( key, properties);
}

Соответственно, объект может быть легко проверен и извлечен с использованием идентификатора .

1
2
3
4
5
6
7
8
public User getUser( final Long id ) {
 final String key = String.format( "user:%s", id );
 
 final String name = ( String )template.opsForHash().get( key, "name" );
 final String email = ( String )template.opsForHash().get( key, "email" );
 
 return new User( id, name, email );
}
Есть много, намного больше, что можно сделать с помощью Redis , я настоятельно рекомендую взглянуть на это. Это, конечно, не серебряная пуля, но она может легко решить многие сложные проблемы. Наконец, позвольте мне показать, как использовать обмен сообщениями в пабе с Redis . Давайте добавим немного больше конфигурации здесь (как часть класса AppConfig):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Bean
MessageListenerAdapter messageListener() {
 return new MessageListenerAdapter( new RedisMessageListener() );
}
 
@Bean
RedisMessageListenerContainer redisContainer() {
 final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
 
 container.setConnectionFactory( jedisConnectionFactory() );
 container.addMessageListener( messageListener(), new ChannelTopic( "my-queue" ) );
 
 return container;
}
Стиль определения прослушивателя сообщений должен выглядеть очень знакомым для пользователей Spring: как правило, мы используем тот же подход для определения прослушивателей сообщений JMS. Пропущенный фрагмент — это наше определение класса RedisMessageListener:
01
02
03
04
05
06
07
08
09
10
11
package com.example.redis.impl;
 
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
 
public class RedisMessageListener implements MessageListener {
 @Override
 public void onMessage(Message message, byte[] paramArrayOfByte) {
  System.out.println( "Received by RedisMessageListener: " + message.toString() );
 }
}
Теперь, когда у нас есть прослушиватель сообщений, давайте посмотрим, как мы можем поместить некоторые сообщения в очередь, используя Redis . Как всегда, все довольно просто:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
@Autowired private RedisTemplate< String, Object > template;
 
public void publish( final String message ) {
 template.execute(
  new RedisCallback< Long >() {
   @SuppressWarnings( "unchecked" )
   @Override
   public Long doInRedis( RedisConnection connection ) throws DataAccessException {
    return connection.publish(
     ( ( RedisSerializer< String > )template.getKeySerializer() ).serialize( "queue" ),
     ( ( RedisSerializer< Object > )template.getValueSerializer() ).serialize( message ) );
   }
  }
 );
}

Это в основном все для очень быстрого знакомства, но этого достаточно, чтобы влюбиться в Redis .

Ссылка: Использование Redis с Spring от нашего партнера по JCG Андрея Редько в блоге Андрея Редько {devmind} .