如何动态设置 Spring Data Cassandra 键空间?
Posted
技术标签:
【中文标题】如何动态设置 Spring Data Cassandra 键空间?【英文标题】:How to set Spring Data Cassandra keyspace dynamically? 【发布时间】:2018-07-23 01:26:05 【问题描述】:我们正在使用带有Spring Data for Apache Cassandra 的 Spring Boot 1.5.10,一切正常。
我们有一个新要求,我们需要在服务启动并运行时连接到不同的键空间。
通过使用 Spring Cloud Config Server,我们可以轻松设置 spring.data.cassandra.keyspace-name
的值,但是,我们不确定是否有一种方法可以动态切换(强制)服务以使用这个新的 keyspace,而无需是否必须先重新启动?
有什么想法或建议吗?
【问题讨论】:
【参考方案1】:将 @RefreshScope
与属性/存储库一起使用不起作用,因为键空间绑定到 Cassandra Session
bean。
将 Spring Data Cassandra 1.5 与 Spring Boot 1.5 一起使用,您至少有两个选择:
-
声明
@RefreshScope
CassandraSessionFactoryBean
,另见CassandraDataAutoConfiguration
。这将在刷新并重新创建所有依赖 bean 时中断所有 Cassandra 操作。
收听RefreshScopeRefreshedEvent
并通过USE my-new-keyspace;
更改键空间。这种方法侵入性较小,并且不会中断正在运行的查询。您基本上会使用事件侦听器。
@Component
class MySessionRefresh
private final Session session;
private final Environment environment;
// omitted constructors for brevity
@EventListener
@Order(Ordered.LOWEST_PRECEDENCE)
public void handle(RefreshScopeRefreshedEvent event)
String keyspace = environment.getProperty("spring.data.cassandra.keyspace-name");
session.execute("USE " + keyspace + ";");
在 Spring Data Cassandra 2 中,我们引入了 SessionFactory
抽象,为 CQL/会话调用的代码控制路由提供了 AbstractRoutingSessionFactory
。
【讨论】:
感谢约翰非常彻底的回复。因为在我只想问一个后续问题之前,我还没有与事件监听器合作过。由于侵入性较小,我真的想使用选项 2,但是,我有点不清楚是否需要为您已经提供的代码创建一个单独的侦听器类?我还没有找到任何使用 RefreshEvent 的例子,所以这里有点黑暗 :-) 我可以看到 @Component 正在工作并且 bean 已创建,但是,我未能触发处理()方法。干杯 我不是约翰。拥有一个自己的类将键空间更改/刷新的所有责任封装在单个类中,您不会混合方面。然而,这是一种最适合这里的格式,而不是组成一个配置类...... 抱歉混淆了你的名字 Mark :-) 我同意你封装责任的推理,我面临的问题是当我调用 / 时没有调用 handle() 方法在服务上刷新端点 - 我是否需要在任何地方注册事件侦听器(我理解它是自动完成的)? 我让您的解决方案在使用“RefreshScopeRefreshedEvent”而不是“RefreshEvent”时正常工作。如果您不介意更新您的答案,我可以接受您的解决方案作为最正确的解决方案。欢呼 抱歉给您带来不便,我已修复并更新为RefreshScopeRefreshedEvent
。【参考方案2】:
是的,您可以在持有spring.data.cassandra.keyspace-name
值的bean 上使用@RefreshScope
注释。
通过 Spring Cloud Config Server 更改配置值后,您必须在应用程序的 /refresh
端点上发出 POST。
来自Spring cloud documentation:
标记为@RefreshScope 的Spring @Bean 将在配置发生更改时得到特殊处理。这解决了只有在初始化时才注入配置的有状态 bean 的问题。例如,如果通过环境更改数据库 URL 时 DataSource 有打开的连接,我们可能希望这些连接的持有者能够完成他们正在做的事情。然后下次有人从池中借用连接时,他会使用新 URL 获得一个。
来自RefreshScope classjavadoc:
允许在运行时动态刷新 Bean 的 Scope 实现(参见 refresh(String) 和 refreshAll())。如果一个 bean 被刷新,那么下次访问该 bean(即执行一个方法)时,就会创建一个新实例。所有生命周期方法都应用于 bean 实例,因此在 bean 工厂中注册的任何销毁回调都会在刷新时调用,然后在创建新实例时正常调用初始化回调。一个新的 bean 实例是从原始 bean 定义创建的,因此任何外部化的内容(字符串文字中的属性占位符或表达式)在创建时都会重新评估。
【讨论】:
这就是我们正在做的事情,但是一旦设置了新的键空间(使用 /refresh 之后),就没有什么可以触发服务开始使用新的键空间了。我不确定这是否可能,因为我认为在服务切换到新的密钥空间之前需要重新启动。 @ASC 你把@RefreshScope
注释放在哪个bean 上?
我把它放在控制器类(@RestController)
你应该试着把它放在仓库里。
John Blum 在 Twitter 上写道:“您可以为启动设置一次密钥空间,然后它会保持不变。”这表明我正在尝试做的事情是不可能的以上是关于如何动态设置 Spring Data Cassandra 键空间?的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Data rest json Response 中动态过滤实体字段