一个为 jCasbin 实现的 Watcher,它利用 PostgreSQL 的 LISTEN/NOTIFY 机制,在分布式多实例环境下,实现策略的自动、实时同步。
- 实时策略同步: 当一个应用实例更新了 Casbin 策略(如增加、删除权限),其他所有实例都能立即收到通知并更新自己的策略缓存。
- 高可靠性: 基于 PostgreSQL 内置的发布/订阅机制,稳定可靠。
- 低延迟:
LISTEN/NOTIFY是一种高效的进程间通信方式,延迟极低。 - 可配置: 支持自定义通知频道、实例ID以及日志开关。
- 避免自我通知: Watcher 实例能够识别并忽略由自身触发的通知,避免不必要的回调。
- 精细化通知: 完全实现了
WatcherEx接口,可以发送带有详细参数的特定策略更新通知(如updateForAddPolicy),而不仅仅是通用的update。
- 每个应用实例在启动时,都会创建一个
JCasbinPostgresWatcher实例。 - 该 Watcher 会向 PostgreSQL 数据库建立一个持久连接,并使用
LISTEN命令监听一个指定的频道(如casbin_psql_watcher)。 - 当某个实例通过
EnforcerAPI 修改了策略后,开发者可以调用对应的WatcherEx方法(如watcher.updateForAddPolicy(...))。Watcher 会将方法名和参数序列化成一个 JSON 字符串,并通过NOTIFY发送出去。 - 所有其他正在监听该频道的 Watcher 实例都会收到这条
NOTIFY消息。 - 收到消息后,Watcher 会触发预设的回调函数。最简单的方式是直接重新加载所有策略(
enforcer.loadPolicy())。高级用法中,也可以解析收到的 JSON 消息,根据不同的更新方法执行不同的操作。
- Java 11 或更高版本
- Apache Maven 3.6+
- PostgreSQL 9.6 或更高版本
将此项目打包安装到您的本地 Maven 仓库,或部署到私有仓库后,在您的 pom.xml 中添加依赖:
<dependency>
<groupId>org.D0000M</groupId>
<artifactId>jcasbin-psql-watcher</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>在您的应用启动代码中,初始化 JCasbinPostgresWatcher 并将其设置给 Enforcer。
简单用法:
import org.casbin.jcasbin.main.Enforcer;
import org.D0000M.watcher.JCasbinPostgresWatcher;
// ...
String url = "jdbc:postgresql://localhost:5432/your_db";
String user = "db_user";
String password = "db_password";
String channel = "my_casbin_channel";
// 初始化 Watcher
JCasbinPostgresWatcher watcher = new JCasbinPostgresWatcher(url, user, password, channel);
// 初始化 Enforcer 并设置 Watcher
Enforcer enforcer = new Enforcer("path/to/model.conf", "path/to/policy.csv");
enforcer.setWatcher(watcher);
// 设置回调函数,当其他实例更新策略时,此函数将被调用
// 经典用法是重新加载策略,适用于所有类型的更新通知
watcher.setUpdateCallback(enforcer::loadPolicy);高级用法 (自定义配置):
您可以传入一个 WatcherConfig 对象来进行更多自定义设置。
import org.D0000M.config.WatcherConfig;
// ...
WatcherConfig config = new WatcherConfig();
config.setChannel("my_casbin_channel"); // 设置频道名称
config.setVerbose(true); // 开启详细日志,用于调试
config.setLocalId("my-app-instance-1"); // 自定义实例ID
JCasbinPostgresWatcher watcher = new JCasbinPostgresWatcher(url, user, password, config);
// ... 后续步骤同上当您修改策略后,应调用 WatcherEx 对应的接口来通知其他实例。
// 在通过 enforcer 添加策略后...
enforcer.addPolicy("alice", "data1", "read");
// ...显式调用 WatcherEx 的方法来广播这个特定的变更
watcher.updateForAddPolicy("p", "p", "alice", "data1", "read");如果您不想在每次收到通知时都全量加载策略,您可以提供一个处理 String 的回调,并自行解析 JSON 消息。
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
// ...
watcher.setUpdateCallback((String message) -> {
try {
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> msgMap = mapper.readValue(message, Map.class);
System.out.println("Received update. Method: " + msgMap.get("method"));
System.out.println("Parameters: " + msgMap.get("params"));
// 在此可根据不同的 method 实现更精细的逻辑
// if ("updateForAddPolicy".equals(msgMap.get("method"))) { ... }
// 为简单起见,此处我们仍然选择完全重新加载
enforcer.loadPolicy();
} catch (Exception e) {
e.printStackTrace();
}
});确保您本地的 PostgreSQL 服务正在运行,并且数据库配置与测试代码中的一致。然后执行:
mvn clean test项目中提供了一个完整的示例 ExampleApp.java,它通过命令行参数来模拟两个独立的应用实例:一个作为"接收方",一个作为"发送方"。
请按照以下步骤来演示 Watcher 的完整功能:
-
打开第一个终端 (作为接收方):
- 进入项目根目录。
- 编译项目:
mvn compile
- 运行接收方程序,它会一直监听策略变更:
mvn exec:java "-Dexec.mainClass=org.D0000M.watcher.ExampleApp" - 您会看到类似
[receiver-app] 作为接收方,正在监听...的输出。请保持此终端窗口运行。
-
打开第二个终端 (作为发送方):
- 也进入项目根目录。
- 运行发送方程序,并附带
send参数。它会模拟一次策略更新,发送通知,然后退出:mvn exec:java "-Dexec.mainClass=org.D0000M.watcher.ExampleApp" "-Dexec.args=send"
-
观察结果:
- 当第二个终端的程序运行时,请立刻观察第一个终端的输出。
- 您应该能看到接收方打印出:
[receiver-app] 检测到策略变更,已回调!... - 这证明了
jcasbin-psql-watcher成功地实现了跨实例的策略同步。
本项目基于 Apache 2.0 License 发布。