篮球小凯 level
获赞
27
粉丝
5
关注
26
看过 TA
347
河北工程大学
2028
Java
IP属地:辽宁
暂未填写个人简介
私信
关注
无面如何呢:这种就是后置处理器,spring的生命周期的事件都相当于通过事件总线applicationcontext发了一个通知,这个相当于一个后置通知,常常用来收集某些特定的bean或者全局后置处理
查看2道真题和解析
0 点赞 评论 收藏
分享
Redis 中一种非常高效的二进制数据结构。核心是通过位(bit)来存储和操作数据,特别适合处理海量的布尔型(是 / 否)数据场景。Bitmap 本质上是 Redis 的 String 类型 的「特殊使用方式」—— String 类型最大能存储 512MB 数据,对应可以存储 512MB * 8 = 4294967296 个位(约 43 亿位)。Redis 的 String 类型 是二进制安全的字节序列,官方规定其最大存储容量为 512MB(字节);而 Bitmap 本质上是对 String 字节的「位级操作」—— 把每个字节(Byte)拆成 8 个位(Bit)来使用,因此 Bitmap 的最大可用位数 = 512MB × 8 = 4294967296 位(约 43 亿位)。每个位只有 0 或 1 两种状态;通过「偏移量(offset)」定位具体的位(偏移量从 0 开始,无上限,只要内存足够);核心价值:用极少的内存存储海量的布尔型数据。512MB 限制的底层原因Redis 对 String 设 512MB 上限,并非技术上无法突破,而是基于「性能 + 设计定位」的权衡:内存与性能平衡:String 是 Redis 最基础、使用最频繁的类型,若允许无限制存储大字符串,会导致:单 key 占用过多内存。读写大 String 时(如 GET/SET 512MB 数据),网络传输、内存拷贝耗时过长,阻塞 Redis 主线程;符合 Redis 设计定位:Redis 是「内存数据库」,核心优势是「高速读写」,适合存储小而高频访问的数据(如缓存、计数器),而非大文件 / 大 blob 数据;底层编码适配:Redis String 会根据长度自动切换编码(int→embstr→raw),超过 44 字节用 raw 编码,512MB 是 raw 编码的安全上限,避免编码切换或内存管理异常。bitmap直观理解比如用 Bitmap 记录「用户是否登录」:offset = 用户 ID,value = 1(登录)/ 0(未登录);记录 1 亿用户的登录状态,仅需 1亿 / 8 = 12.5MB 内存,远低于用 Hash/Set 等结构的内存消耗。实际操作所有命令都有 BIT1. 设置指定偏移量的位值:SETBIT key offset value(重要)作用:给 key 的第 offset 位设置值(0 或 1)示例:记录用户 ID=10086 的用户今天(20260106)登录了(设为 1):SETBIT login:20260106 10086 1(integer) 0  # 返回值:该位原来的值(首次设置为0)2 获取指定偏移量的位值:GETBIT key offset(重)查询 key 的第 offset 位的值;示例:查询用户 10086 20260106 是否登录:GETBIT login:20260106 100863. 统计指定范围内值为 1 的位数量:(重)BITCOUNT key [start end]统计 key 中值为 1 的位的总数(可选指定字节范围,默认全部)BITCOUNT login:202601064位运算(与 / 或 / 异或 / 非):BITOP operation destkey key1 [key2 ...]作用:对多个 Bitmap 执行位运算,结果存入 destkey;常用运算:AND:与(都为 1 才为 1);OR:或(任意一个为 1 则为 1);XOR:异或(不同为 1,相同为 0);示例:统计用户「20260105 和 20260106 两天都登录」的数量:SETBIT login:20260105 10086 1SETBIT login:20260105 10000 1SETBIT login:20260106 10086 1SETBIT login:20260106 10001 1执行AND运算,结果存入 login:20260105_06_bothBITOP AND login:20260105_06_both login:20260105 login:20260106统计结果(只有10086两天都登录)BITCOUNT login:20260105_06_both
0 点赞 评论 收藏
分享
考虑一种场景,我们的短信发送接口被同一个人使用不同的手机号多次恶意调用,那么同样会导致之前说过的问题。要实现 IP 地址黑名单功能,核心是基于 IP 标识请求方,并通过 Redis 维护黑名单列表,结合拦截器在请求入口处校验。在redisconstants中// ========== 新增【登录IP管控】核心配置 ==========// IP 1分钟限流Key(格式:verify:ip:limit:xxx.xxx.xxx.xxx):1IP1分钟仅能发1次验证码public static final String VERIFY_IP_LIMIT_KEY = "verify:ip:limit:";// IP请求次数统计Key(格式:verify:ip:count:xxx.xxx.xxx.xxx):统计短时间内IP总请求数public static final String VERIFY_IP_COUNT_KEY = "verify:ip:count:";// IP黑名单Key(格式:verify:ip:black:xxx.xxx.xxx.xxx):IP被封禁的标识public static final String VERIFY_IP_BLACK_KEY = "verify:ip:black:";// 通用过期时间(复用原有,无需新增):限流60s、统计1h、黑名单24h在usersericeimpl中//ip黑名单检测// 从session中获取HttpServletRequest对象HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// ====== 第一步:获取客户端真实IP(必须!适配本地/服务器/代理环境) ======String clientIp = getRealIp(request);// ====== 第二步:校验黑名单【优先级最高】 ======// 1. 校验IP是否在黑名单 → IP拉黑直接拒绝String ipBlackKey = RedisConstants.VERIFY_IP_BLACK_KEY + clientIp;if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(ipBlackKey))) {return Result.fail("ip在黑名单中!!");}// ====== 第三步:校验1分钟限流【防高频请求】 ======// 1. 校验IP:同一个IP,1分钟内仅能请求1次String ipLimitKey = RedisConstants.VERIFY_IP_LIMIT_KEY + clientIp;if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(ipLimitKey))) {return Result.fail("同一个IP,1分钟内仅能请求1次");}// 1. IP请求次数统计:短时间内超3次 → 拉黑IPString ipCountKey = RedisConstants.VERIFY_IP_COUNT_KEY + clientIp;Long ipCount = stringRedisTemplate.opsForValue().increment(ipCountKey);if (ipCount == 1) { // 首次请求,设置1小时过期stringRedisTemplate.expire(ipCountKey, RedisConstants.VERIFY_COUNT_TTL, TimeUnit.SECONDS);}// IP超3次 → 封禁IP(24小时)if (ipCount > 2) {stringRedisTemplate.opsForValue().set(ipBlackKey, "1", RedisConstants.VERIFY_BLACK_TTL, TimeUnit.SECONDS);}// ========== 工具方法1:获取客户端真实IP(关键!适配所有环境) ==========private String getRealIp(HttpServletRequest request) {String ip = request.getHeader("X-Forwarded-For");if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}// 处理多代理场景,取第一个有效IPif (ip != null && ip.contains(",")) {ip = ip.split(",")[0].trim();}return ip;}// ========== 工具方法2:超阈值时,清理无用的限流/统计Key ==========private void cleanLimitKey(String... keys) {for (String key : keys) {stringRedisTemplate.delete(key);}}
0 点赞 评论 收藏
分享

创作者周榜

更多
关注他的用户也关注了:
牛客网
牛客网在线编程
牛客网题解
牛客企业服务