From c516aa145ec31430d3f12fff81a507ff9d163664 Mon Sep 17 00:00:00 2001 From: lbs <2322701154@qq.com> Date: Fri, 9 Jan 2026 20:52:54 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=E5=AE=9E=E7=8E=B0=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E7=BC=96=E8=AF=91=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../arthas/core/util/RegexCacheManager.java | 65 +++++++++++ .../core/util/matcher/RegexMatcher.java | 10 +- .../core/util/RegexCacheManagerTest.java | 107 ++++++++++++++++++ 3 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java create mode 100644 core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java diff --git a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java new file mode 100644 index 00000000000..e1cb4a5dc10 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java @@ -0,0 +1,65 @@ +package com.taobao.arthas.core.util; + +import com.taobao.arthas.core.shell.term.impl.http.session.LRUCache; +import java.util.regex.Pattern; + +/** + * 正则表达式缓存管理器 + * 用于缓存编译后的正则表达式对象,避免重复编译的开销 + */ +public class RegexCacheManager { + private static final RegexCacheManager INSTANCE = new RegexCacheManager(); + + // 使用 LRUCache 替代 ConcurrentHashMap + private final LRUCache regexCache; + + // 缓存大小限制 + private static final int MAX_CACHE_SIZE = 100; + + private RegexCacheManager() { + // 初始化 LRUCache,设置最大缓存大小 + this.regexCache = new LRUCache<>(MAX_CACHE_SIZE); + } + + public static RegexCacheManager getInstance() { + return INSTANCE; + } + + /** + * 获取正则表达式Pattern对象,优先从缓存获取,缓存未命中则编译并缓存 + */ + public Pattern getPattern(String regex) { + if (regex == null || regex.isEmpty()) { + return null; + } + + // 从 LRUCache 获取 + Pattern pattern = regexCache.get(regex); + if (pattern != null) { + return pattern; + } + + // 缓存未命中,编译正则表达式 + pattern = Pattern.compile(regex); + + // 缓存编译结果 + regexCache.put(regex, pattern); + + return pattern; + } + + /** + * 清理缓存 + */ + public void clearCache() { + regexCache.clear(); + } + + /** + * 获取缓存大小 + */ + public int getCacheSize() { + return regexCache.usedEntries(); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java b/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java index 1998265e365..64e0c4cee64 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java +++ b/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java @@ -1,21 +1,25 @@ package com.taobao.arthas.core.util.matcher; +import com.taobao.arthas.core.util.RegexCacheManager; +import java.util.regex.Pattern; + /** * regex matcher * @author ralf0131 2017-01-06 13:16. */ public class RegexMatcher implements Matcher { - private final String pattern; + private final Pattern pattern; public RegexMatcher(String pattern) { - this.pattern = pattern; + // 使用正则表达式缓存 + this.pattern = RegexCacheManager.getInstance().getPattern(pattern); } @Override public boolean matching(String target) { return null != target && null != pattern - && target.matches(pattern); + && pattern.matcher(target).matches(); } } \ No newline at end of file diff --git a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java new file mode 100644 index 00000000000..3635d83c41d --- /dev/null +++ b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java @@ -0,0 +1,107 @@ +package com.taobao.arthas.core.util; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.regex.Pattern; + +/** + * RegexCacheManager测试类 + */ +public class RegexCacheManagerTest { + private RegexCacheManager cacheManager; + + @Before + public void setUp() { + // 获取单例实例 + cacheManager = RegexCacheManager.getInstance(); + // 清理缓存,确保测试环境干净 + cacheManager.clearCache(); + } + + /** + * 测试基本缓存功能 + */ + @Test + public void testBasicCacheFunctionality() { + // 测试缓存未命中的情况 + String regex1 = ".*Test.*"; + Pattern pattern1 = cacheManager.getPattern(regex1); + Assert.assertNotNull(pattern1); + Assert.assertEquals(1, cacheManager.getCacheSize()); + + // 测试缓存命中的情况 + Pattern pattern1Cached = cacheManager.getPattern(regex1); + Assert.assertNotNull(pattern1Cached); + Assert.assertSame(pattern1, pattern1Cached); // 应该是同一个对象 + Assert.assertEquals(1, cacheManager.getCacheSize()); // 缓存大小应该保持不变 + + // 测试多个正则表达式 + String regex2 = "^Test.*"; + Pattern pattern2 = cacheManager.getPattern(regex2); + Assert.assertNotNull(pattern2); + Assert.assertEquals(2, cacheManager.getCacheSize()); + + // 测试空正则表达式 + Pattern nullPattern = cacheManager.getPattern(null); + Assert.assertNull(nullPattern); + + Pattern emptyPattern = cacheManager.getPattern(""); + Assert.assertNull(emptyPattern); + } + + /** + * 测试LRU淘汰策略 + */ + @Test + public void testLRUEvictionPolicy() { + // 生成多个正则表达式,超过最大缓存大小 + int maxCacheSize = 100; + for (int i = 0; i < maxCacheSize + 5; i++) { + String regex = "TestRegex" + i; + Pattern pattern = cacheManager.getPattern(regex); + Assert.assertNotNull(pattern); + } + + // 缓存大小应该等于最大缓存大小 + Assert.assertTrue(cacheManager.getCacheSize() <= 100); // 100 是实际的最大缓存大小 + + // 测试访问顺序,确保 LRU 策略生效 + String firstRegex = "TestRegex0"; + + // 再次访问第一个正则表达式,使其成为最近使用的 + Pattern firstPattern = cacheManager.getPattern(firstRegex); + Assert.assertNotNull(firstPattern); + + // 再添加一个新的正则表达式,应该淘汰最久未使用的 + String newRegex = "NewTestRegex"; + Pattern newPattern = cacheManager.getPattern(newRegex); + Assert.assertNotNull(newPattern); + + // 第一个正则表达式应该仍然在缓存中(因为刚被访问过) + Pattern firstPatternAgain = cacheManager.getPattern(firstRegex); + Assert.assertNotNull(firstPatternAgain); + } + + /** + * 测试缓存清理功能 + */ + @Test + public void testCacheClear() { + // 添加一些缓存项 + cacheManager.getPattern(".*Test1"); + cacheManager.getPattern(".*Test2"); + Assert.assertTrue(cacheManager.getCacheSize() > 0); + + // 清理缓存 + cacheManager.clearCache(); + Assert.assertEquals(0, cacheManager.getCacheSize()); + + // 清理后应该可以重新添加缓存项 + Pattern pattern = cacheManager.getPattern(".*Test3"); + Assert.assertNotNull(pattern); + Assert.assertEquals(1, cacheManager.getCacheSize()); + } + +} From 712f2b70b699ab42774bc68202ec80f66b9f53cb Mon Sep 17 00:00:00 2001 From: lbs <2322701154@qq.com> Date: Fri, 9 Jan 2026 22:12:52 +0800 Subject: [PATCH 2/6] =?UTF-8?q?fix:=E5=AE=9E=E7=8E=B0=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=AE=89=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../arthas/core/util/RegexCacheManager.java | 28 +++++++++++++------ .../core/util/RegexCacheManagerTest.java | 23 +++++++++++++-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java index e1cb4a5dc10..efb82b59b45 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java +++ b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java @@ -2,6 +2,7 @@ import com.taobao.arthas.core.shell.term.impl.http.session.LRUCache; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; /** * 正则表达式缓存管理器 @@ -10,14 +11,14 @@ public class RegexCacheManager { private static final RegexCacheManager INSTANCE = new RegexCacheManager(); - // 使用 LRUCache 替代 ConcurrentHashMap + // 使用LRUCache缓存编译后的正则表达式 private final LRUCache regexCache; // 缓存大小限制 private static final int MAX_CACHE_SIZE = 100; private RegexCacheManager() { - // 初始化 LRUCache,设置最大缓存大小 + // 初始化LRUCache,设置最大缓存大小 this.regexCache = new LRUCache<>(MAX_CACHE_SIZE); } @@ -32,18 +33,27 @@ public Pattern getPattern(String regex) { if (regex == null || regex.isEmpty()) { return null; } - - // 从 LRUCache 获取 + + // 从LRUCache获取 Pattern pattern = regexCache.get(regex); if (pattern != null) { return pattern; } - // 缓存未命中,编译正则表达式 - pattern = Pattern.compile(regex); - - // 缓存编译结果 - regexCache.put(regex, pattern); + // 使用双重检查锁,避免并发情况下重复编译相同的正则 + synchronized (regexCache) { + pattern = regexCache.get(regex); + if (pattern == null) { + try { + // 缓存未命中,编译正则表达式 + pattern = Pattern.compile(regex); + regexCache.put(regex, pattern); + } catch (PatternSyntaxException e) { + // 捕获正则表达式语法错误,返回null,保持与原来相同的错误处理行为 + return null; + } + } + } return pattern; } diff --git a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java index 3635d83c41d..0c0c84c1981 100644 --- a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java +++ b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java @@ -65,9 +65,9 @@ public void testLRUEvictionPolicy() { } // 缓存大小应该等于最大缓存大小 - Assert.assertTrue(cacheManager.getCacheSize() <= 100); // 100 是实际的最大缓存大小 + Assert.assertEquals(maxCacheSize, cacheManager.getCacheSize()); // 100 是实际的最大缓存大小 - // 测试访问顺序,确保 LRU 策略生效 + // 测试访问顺序,确保LRU策略生效 String firstRegex = "TestRegex0"; // 再次访问第一个正则表达式,使其成为最近使用的 @@ -104,4 +104,23 @@ public void testCacheClear() { Assert.assertEquals(1, cacheManager.getCacheSize()); } + /** + * 测试无效正则表达式处理 + */ + @Test + public void testInvalidRegexHandling() { + // 测试无效的正则表达式 + String invalidRegex = "[a-z"; + Pattern pattern = cacheManager.getPattern(invalidRegex); + Assert.assertNull(pattern); + + // 测试另一个无效的正则表达式 + String anotherInvalidRegex = "(a-z"; + Pattern anotherPattern = cacheManager.getPattern(anotherInvalidRegex); + Assert.assertNull(anotherPattern); + + // 确保缓存大小没有增加 + Assert.assertEquals("无效正则表达式不应该被缓存", 0, cacheManager.getCacheSize()); + } + } From 31b1ad648db37ef5068ffc4d670441ddc2df9521 Mon Sep 17 00:00:00 2001 From: lbs <2322701154@qq.com> Date: Fri, 9 Jan 2026 23:42:35 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix:=E6=8A=9B=E5=87=BAPatternSyntaxExceptio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../arthas/core/util/RegexCacheManager.java | 14 +++++--------- .../core/util/matcher/RegexMatcher.java | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java index efb82b59b45..355fdfb1c94 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java +++ b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java @@ -2,7 +2,6 @@ import com.taobao.arthas.core.shell.term.impl.http.session.LRUCache; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; /** * 正则表达式缓存管理器 @@ -44,14 +43,11 @@ public Pattern getPattern(String regex) { synchronized (regexCache) { pattern = regexCache.get(regex); if (pattern == null) { - try { - // 缓存未命中,编译正则表达式 - pattern = Pattern.compile(regex); - regexCache.put(regex, pattern); - } catch (PatternSyntaxException e) { - // 捕获正则表达式语法错误,返回null,保持与原来相同的错误处理行为 - return null; - } + // 缓存未命中,编译正则表达式 + // 不捕获PatternSyntaxException,让异常向上抛出,以便及时发现无效的正则表达式 + pattern = Pattern.compile(regex); + // 缓存编译结果 + regexCache.put(regex, pattern); } } diff --git a/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java b/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java index 64e0c4cee64..1709c5d31e1 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java +++ b/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java @@ -9,17 +9,24 @@ */ public class RegexMatcher implements Matcher { - private final Pattern pattern; + private final String pattern; + private Pattern compiledPattern; public RegexMatcher(String pattern) { - // 使用正则表达式缓存 - this.pattern = RegexCacheManager.getInstance().getPattern(pattern); + this.pattern = pattern; } @Override public boolean matching(String target) { - return null != target - && null != pattern - && pattern.matcher(target).matches(); + if (null == target || null == pattern) { + return false; + } + + // 在第一次matching时才编译正则表达式 + if (compiledPattern == null) { + compiledPattern = RegexCacheManager.getInstance().getPattern(pattern); + } + + return compiledPattern != null && compiledPattern.matcher(target).matches(); } } \ No newline at end of file From 3aa20584e48173bab907021fbb6cce584b3863ab Mon Sep 17 00:00:00 2001 From: lbs <2322701154@qq.com> Date: Sat, 10 Jan 2026 00:46:12 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8DtestInvalidRegexHandl?= =?UTF-8?q?ing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/util/RegexCacheManagerTest.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java index 0c0c84c1981..7154552429e 100644 --- a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java +++ b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java @@ -109,15 +109,21 @@ public void testCacheClear() { */ @Test public void testInvalidRegexHandling() { - // 测试无效的正则表达式 + // 测试无效的正则表达式,应该抛出PatternSyntaxException String invalidRegex = "[a-z"; - Pattern pattern = cacheManager.getPattern(invalidRegex); - Assert.assertNull(pattern); + try { + cacheManager.getPattern(invalidRegex); + } catch (Exception e) { + // 预期会抛出异常 + } - // 测试另一个无效的正则表达式 + // 测试另一个无效的正则表达式,应该抛出PatternSyntaxException String anotherInvalidRegex = "(a-z"; - Pattern anotherPattern = cacheManager.getPattern(anotherInvalidRegex); - Assert.assertNull(anotherPattern); + try { + cacheManager.getPattern(anotherInvalidRegex); + } catch (Exception e) { + // 预期会抛出异常 + } // 确保缓存大小没有增加 Assert.assertEquals("无效正则表达式不应该被缓存", 0, cacheManager.getCacheSize()); From 510071a7b39a029e5c4f6658ebcb5ad3e173c58f Mon Sep 17 00:00:00 2001 From: lbs <2322701154@qq.com> Date: Sat, 10 Jan 2026 13:48:25 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=E5=8E=BB=E9=99=A4RegexCacheManager?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=86=97=E4=BD=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../arthas/core/util/RegexCacheManager.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java index 355fdfb1c94..bf05a8c6c2e 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java +++ b/core/src/main/java/com/taobao/arthas/core/util/RegexCacheManager.java @@ -39,17 +39,11 @@ public Pattern getPattern(String regex) { return pattern; } - // 使用双重检查锁,避免并发情况下重复编译相同的正则 - synchronized (regexCache) { - pattern = regexCache.get(regex); - if (pattern == null) { - // 缓存未命中,编译正则表达式 - // 不捕获PatternSyntaxException,让异常向上抛出,以便及时发现无效的正则表达式 - pattern = Pattern.compile(regex); - // 缓存编译结果 - regexCache.put(regex, pattern); - } - } + // 缓存未命中,编译正则表达式 + // 不捕获PatternSyntaxException,让异常向上抛出,以便及时发现无效的正则表达式 + pattern = Pattern.compile(regex); + // 缓存编译结果 + regexCache.put(regex, pattern); return pattern; } From d5574cef0b0f3471c7dbe314136dcc32d9c011c2 Mon Sep 17 00:00:00 2001 From: lbs <2322701154@qq.com> Date: Sat, 10 Jan 2026 20:35:41 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix:volatile=20Pattern=E5=B9=B6=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=AE=8C=E5=96=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/taobao/arthas/core/util/matcher/RegexMatcher.java | 2 +- .../com/taobao/arthas/core/util/RegexCacheManagerTest.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java b/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java index 1709c5d31e1..e423205075c 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java +++ b/core/src/main/java/com/taobao/arthas/core/util/matcher/RegexMatcher.java @@ -10,7 +10,7 @@ public class RegexMatcher implements Matcher { private final String pattern; - private Pattern compiledPattern; + private volatile Pattern compiledPattern; public RegexMatcher(String pattern) { this.pattern = pattern; diff --git a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java index 7154552429e..240a97585cc 100644 --- a/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java +++ b/core/src/test/java/com/taobao/arthas/core/util/RegexCacheManagerTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; /** * RegexCacheManager测试类 @@ -114,7 +115,8 @@ public void testInvalidRegexHandling() { try { cacheManager.getPattern(invalidRegex); } catch (Exception e) { - // 预期会抛出异常 + // 验证抛出的是PatternSyntaxException + Assert.assertTrue("Expected PatternSyntaxException but got " + e.getClass().getName(), e instanceof PatternSyntaxException); } // 测试另一个无效的正则表达式,应该抛出PatternSyntaxException @@ -122,7 +124,8 @@ public void testInvalidRegexHandling() { try { cacheManager.getPattern(anotherInvalidRegex); } catch (Exception e) { - // 预期会抛出异常 + // 验证抛出的是PatternSyntaxException + Assert.assertTrue("Expected PatternSyntaxException but got " + e.getClass().getName(), e instanceof PatternSyntaxException); } // 确保缓存大小没有增加