如何在过期事件中访问spring data redis store对象?
Posted
技术标签:
【中文标题】如何在过期事件中访问spring data redis store对象?【英文标题】:How to acess spring data redis stored object at the expiration event? 【发布时间】:2020-09-19 04:22:32 【问题描述】:我使用 Spring Data Redis 将购物车存储在 Redis 中特定时间。使用 @TimeToLive 注释的过期属性设置 Cart 对象的生存时间,如下面的代码所述。
我设置了KeyExpirationEventMessageListener
类型来监听过期事件,以便在过期事件中处理额外的工作。我能够从过期对象的触发事件中获取密钥,并且我试图在过期时使用 spring 数据存储库访问它或其幻像对象,但没有结果。它返回一个空对象,这意味着原始对象对象很可能已被删除。我不知道这是否是正确的方法。但是,有没有办法在到期时或在它被删除以处理移动工作之前获取到期对象?
@RedisHash("cart")
public class Cart implements Serializable
@Id
@Indexed
private String id;
private long customerId;
private Set<CartLine> lines = new HashSet<>();
@TimeToLive
private long expiration;
public interface ShoppingCartRepository extends CrudRepository<Cart, String>
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener
private RedisTemplate<?, ?> redisTemplate;
private ShoppingCartRepository repository;
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer,
RedisTemplate redisTemplate, ShoppingCartRepository repository)
super(listenerContainer);
this.redisTemplate = redisTemplate;
this.repository = repository;
@Override
public void onMessage(Message message, byte[] pattern)
String key = new String(message.getBody());
try
String id = extractId(key);
Optional<ShoppingCart> cart = repository.findById(id);
catch(Exception e)
logger.info("something went wrong ====> " + e.getStackTrace());
private String extractId(String key)
String keyPrefix = ShoppingCart.class.getAnnotation(RedisHash.class).value();
return key.substring((keyPrefix + ":").length());
【问题讨论】:
【参考方案1】:使用 Spring boot 2.3.4.RELEASE 的示例
@RedisHash("cart")
@AllArgsConstructor
@Getter
@Setter
public class Cart implements Serializable
@Id
@Indexed
private String id;
private String customerName;
@TimeToLive
private long expiration;
public interface ShoppingCartRepository extends CrudRepository<Cart, String>
@SpringBootApplication
@EnableRedisRepositories(enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
public class RedisExpirationApplication
public static void main(String[] args)
SpringApplication.run(RedisExpirationApplication.class, args);
@Bean
public CommandLineRunner run(ShoppingCartRepository shoppingCartRepository)
return args ->
// TTL 1 second
shoppingCartRepository.save(new Cart("some-id", "My Customer Name", 1));
// wait 5 seconds
Thread.sleep(5000L);
;
@Component
public class CartListener
// need to enable redis notifications, inside redis-cli type:
// config set notify-keyspace-events KEA
@EventListener
public void anything(RedisKeyExpiredEvent<Cart> expiredCart)
Cart cart = (Cart) expiredCart.getValue();
System.out.println(cart.getId());
System.out.println(cart.getCustomerName());
【讨论】:
感谢 Nilzao,与 Spring Boot 2.3.4 完美集成。这工作得很好。 @ROUISSIMohamedALi 您是使用属性enableKeyspaceEvents
在代码中启用键空间事件还是从 Redis 控制台手动启用?
@AbhijitSarkar 我是从 Redis 控制台手动完成的。【参考方案2】:
我的场景里曾经有一个用例,其实可以使用RedisKeyExpiredEvent,
RedisKeyExpiredEvent [0] 是发布的特定于 Redis 的 ApplicationEvent 当 Redis 中的特定键过期时。它可以保持的价值 密钥旁边的过期密钥。您可以继续执行以下操作。
@SpringBootApplication
@EnableRedisRepositories(considerNestedRepositories = true, enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP)
static class Config
/**
* An @link ApplicationListener that captures @link RedisKeyExpiredEvents and just prints the value to the
* console.
*
* @return
*/
@Bean
ApplicationListener<RedisKeyExpiredEvent<Person>> eventListener()
return event ->
System.out.println(String.format("Received expire event for key=%s with value %s.",
new String(event.getSource()), event.getValue()));
;
您可以在 [1] 找到示例实现。
[0]https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisKeyExpiredEvent.html#getValue-- [1]https://github.com/christophstrobl/next-level-redis-with-spring/blob/master/src/test/java/org/example/repository/RepsoitoryTests.java#L57
【讨论】:
我在起始类的顶部添加了@EnableRedisRepositories(considerNestedRepositories = true, enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP)
,并在我的自定义购物车对象中添加了 eventListener() Bean。但是当它过期时,不会调用 lambda 函数。我也尝试将其用作组件,但 onApplicationEvent
方法没有被调用
您是否尝试正确调试,您确定代码已正确实现。你能给我任何日志或示例实现,我可以检查它在我的本地实例上运行。
是的,我也尝试过调试。这是一个基本工作的示例代码库bitbucket.org/marouissi/springdataredis/src/master
嘿 Anuj 你有机会看到这个代码示例吗?你能做到吗以上是关于如何在过期事件中访问spring data redis store对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Data Redis 为过期键启用键空间通知
如何将默认过期的 RedisCacheManager 迁移到 Spring Data Redis 2.0?