fix advice listener snapshot registration (#3209)

This commit is contained in:
hengyunabc
2026-06-06 20:49:24 +08:00
committed by GitHub
parent f3e065c61b
commit 4aac69fb46
2 changed files with 120 additions and 18 deletions
@@ -116,15 +116,7 @@ public class AdviceListenerManager {
synchronized (this) {
className = className.replace('/', '.');
String key = key(className, methodName, methodDesc);
List<AdviceListener> listeners = map.get(key);
if (listeners == null) {
listeners = new ArrayList<AdviceListener>();
map.put(key, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
registerListener(key, listener);
}
}
@@ -142,18 +134,23 @@ public class AdviceListenerManager {
synchronized (this) {
className = className.replace('/', '.');
String key = keyForTrace(className, owner, methodName, methodDesc);
List<AdviceListener> listeners = map.get(key);
if (listeners == null) {
listeners = new ArrayList<AdviceListener>();
map.put(key, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
registerListener(key, listener);
}
}
private void registerListener(String key, AdviceListener listener) {
List<AdviceListener> listeners = map.get(key);
if (listeners != null && listeners.contains(listener)) {
return;
}
List<AdviceListener> newListeners = listeners == null
? new ArrayList<AdviceListener>()
: new ArrayList<AdviceListener>(listeners);
newListeners.add(listener);
map.put(key, newListeners);
}
public List<AdviceListener> queryTraceAdviceListeners(String className, String owner, String methodName,
String methodDesc) {
className = className.replace('/', '.');
@@ -0,0 +1,105 @@
package com.taobao.arthas.core.advisor;
import java.util.Iterator;
import java.util.List;
import org.assertj.core.api.Assertions;
import org.junit.Test;
public class AdviceListenerManagerTest {
@Test
public void queryAdviceListenersShouldReturnStableSnapshotWhenRegisteringAnotherListener() {
AdviceListenerManager.ClassLoaderAdviceListenerManager manager =
new AdviceListenerManager.ClassLoaderAdviceListenerManager();
TestAdviceListener first = new TestAdviceListener(1);
TestAdviceListener second = new TestAdviceListener(2);
manager.registerAdviceListener("demo.MathGame", "primeFactors", "(I)Ljava/util/List;", first);
List<AdviceListener> listeners = manager.queryAdviceListeners("demo.MathGame", "primeFactors",
"(I)Ljava/util/List;");
Iterator<AdviceListener> iterator = listeners.iterator();
Assertions.assertThat(iterator.next()).isSameAs(first);
manager.registerAdviceListener("demo.MathGame", "primeFactors", "(I)Ljava/util/List;", second);
Assertions.assertThatCode(new org.assertj.core.api.ThrowableAssert.ThrowingCallable() {
@Override
public void call() {
while (iterator.hasNext()) {
iterator.next();
}
}
}).doesNotThrowAnyException();
Assertions.assertThat(listeners).containsExactly(first);
Assertions.assertThat(manager.queryAdviceListeners("demo.MathGame", "primeFactors", "(I)Ljava/util/List;"))
.containsExactly(first, second);
}
@Test
public void queryTraceAdviceListenersShouldReturnStableSnapshotWhenRegisteringAnotherListener() {
AdviceListenerManager.ClassLoaderAdviceListenerManager manager =
new AdviceListenerManager.ClassLoaderAdviceListenerManager();
TestAdviceListener first = new TestAdviceListener(1);
TestAdviceListener second = new TestAdviceListener(2);
manager.registerTraceAdviceListener("demo.MathGame", "java/lang/StringBuilder", "append",
"(I)Ljava/lang/StringBuilder;", first);
List<AdviceListener> listeners = manager.queryTraceAdviceListeners("demo.MathGame", "java/lang/StringBuilder",
"append", "(I)Ljava/lang/StringBuilder;");
Iterator<AdviceListener> iterator = listeners.iterator();
Assertions.assertThat(iterator.next()).isSameAs(first);
manager.registerTraceAdviceListener("demo.MathGame", "java/lang/StringBuilder", "append",
"(I)Ljava/lang/StringBuilder;", second);
Assertions.assertThatCode(new org.assertj.core.api.ThrowableAssert.ThrowingCallable() {
@Override
public void call() {
while (iterator.hasNext()) {
iterator.next();
}
}
}).doesNotThrowAnyException();
Assertions.assertThat(listeners).containsExactly(first);
Assertions.assertThat(manager.queryTraceAdviceListeners("demo.MathGame", "java/lang/StringBuilder", "append",
"(I)Ljava/lang/StringBuilder;")).containsExactly(first, second);
}
private static class TestAdviceListener implements AdviceListener {
private final long id;
private TestAdviceListener(long id) {
this.id = id;
}
@Override
public long id() {
return id;
}
@Override
public void create() {
}
@Override
public void destroy() {
}
@Override
public void before(Class<?> clazz, String methodName, String methodDesc, Object target, Object[] args) {
}
@Override
public void afterReturning(Class<?> clazz, String methodName, String methodDesc, Object target, Object[] args,
Object returnObject) {
}
@Override
public void afterThrowing(Class<?> clazz, String methodName, String methodDesc, Object target, Object[] args,
Throwable throwable) {
}
}
}