最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何借助EnumSet在权限校验拦截器中实现O(1)时间复杂度的极速路由权限判定
时间:2026-06-23 08:21:58 编辑:袖梨 来源:一聚教程网
EnumSet做权限校验可实现严格O(1)判定,核心是权限枚举按声明顺序映射位索引,预构建不可变集并用containsAll进行位运算比对。
用 EnumSet 做权限校验,核心在于把权限抽象为枚举,再利用其底层位运算特性实现真正的 O(1) 判定——不是“接近 O(1)”,而是实实在在的常数时间查集操作。
权限必须定义为 enum,且按位幂次排列
EnumSet 内部使用 long 或 bit vector 存储,但前提是枚举值的声明顺序决定其位索引。JVM 会按声明顺序给每个枚举常量分配一个序号(ordinal()),EnumSet 正是基于这个序号做位标记。所以权限枚举必须显式按 2 的幂次设计,确保每个权限独占一位:
- 不要写:
READ, WRITE, DELETE(ordinal=0,1,2 → 位重叠,无法位运算区分) - 要写:
READ(1), WRITE(2), DELETE(4), ADMIN(8),并重载ordinal()或直接靠构造器控制顺序 - 更稳妥做法:用
enum Permission { READ, WRITE, DELETE, ADMIN },不赋值,只依赖声明顺序,并保证总数 ≤64(RegularEnumSet用 long;超 64 会退化为JumboEnumSet,仍 O(1),但内存略增)
拦截器中预构建用户权限集,避免运行时重复创建
每次请求都 new 一个 EnumSet 是低效的。应在用户登录或权限加载时,一次性构建不可变权限集:
- 用
EnumSet.copyOf(Collection<Permission>)或EnumSet.of(p1, p2, ...)构建 - 立即包装为
EnumSet.unmodifiableEnumSet(...),防止误修改 - 存入 ThreadLocal、SecurityContext 或用户会话缓存中,供拦截器直接 get
路由权限判定只需一次 containsAll(),本质是位与运算
假设接口所需权限是 EnumSet.of(READ, WRITE),用户权限集是 userPerms,判定逻辑就是:
boolean hasAccess = userPerms.containsAll(requiredPerms);
这行代码背后不是遍历,而是:
- 将
requiredPerms所有元素对应位取出,组成 mask - 对
userPerms的位向量执行(userBits & requiredMask) == requiredMask - 纯位运算,CPU 一条指令即可完成,严格 O(1)
配合 Spring Security 或自定义拦截器的轻量集成
在 HandlerInterceptor.preHandle 中,从 request 提取用户上下文,拿到预构建的 EnumSet<Permission>,再比对当前请求路径绑定的权限元数据(可存在注解、配置中心或路由表中):
- 例如:用
@RequirePermission({READ, WRITE})标记 Controller 方法,通过 ReflectionUtils 提前解析并缓存到 Map<String, EnumSet> 中 - 拦截时仅需
pathToPermissions.get(request.getRequestURI()).containsAll(userPerms)—— 注意这里应是userPerms.containsAll(required),方向别反 - 拒绝时直接返回 403,不放行
不复杂但容易忽略:EnumSet 的高性能完全依赖枚举定义规范和预构建习惯。一旦写成动态 new 或权限乱序,就退化成普通 Set 查找。
相关文章
- 《和平精英》50v50模式怎么进入-50v50模式进入方法 06-25
- hive archive 是否支持数据恢复测试 06-25
- hive archive如何执行数据备份 06-25
- hive archive怎样进行数据恢复 06-25
- 《和平精英》周报怎么查看-周报查看方法 06-25
- 老福特怎么免费访问 06-25