switch to SpyAPI, clean Spy code

This commit is contained in:
hengyunabc 2020-05-20 02:54:12 +08:00
parent a55b471ea7
commit 1e52ea4530
5 changed files with 18 additions and 168 deletions

View File

@ -1,6 +1,5 @@
package com.taobao.arthas.agent3;
import java.arthas.Spy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
@ -19,7 +18,6 @@ import com.taobao.arthas.agent.ArthasClassloader;
* @author vlinux on 15/5/19.
*/
public class AgentBootstrap {
private static final String RESET = "resetArthasClassLoader";
private static final String ARTHAS_SPY_JAR = "arthas-spy.jar";
private static final String ARTHAS_CORE_JAR = "arthas-core.jar";
private static final String ARTHAS_BOOTSTRAP = "com.taobao.arthas.core.server.ArthasBootstrap";
@ -79,7 +77,7 @@ public class AgentBootstrap {
Class<?> spyClass = null;
if (parent != null) {
try {
parent.loadClass("java.arthas.Spy");
parent.loadClass("java.arthas.SpyAPI");
} catch (Throwable e) {
// ignore
}
@ -99,10 +97,6 @@ public class AgentBootstrap {
return arthasClassLoader;
}
private static void initSpy() throws NoSuchMethodException {
Spy.AGENT_RESET_METHOD = AgentBootstrap.class.getMethod(RESET);
}
private static synchronized void main(String args, final Instrumentation inst) {
try {
ps.println("Arthas server agent start...");
@ -155,7 +149,6 @@ public class AgentBootstrap {
* Use a dedicated thread to run the binding logic to prevent possible memory leak. #195
*/
final ClassLoader agentLoader = getClassLoader(inst, spyJarFile, arthasCoreJarFile);
initSpy();
Thread bindingThread = new Thread() {
@Override

View File

@ -1,6 +1,6 @@
package com.taobao.arthas.core.server;
import java.arthas.Spy;
import java.arthas.SpyAPI;
import java.io.File;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
@ -26,7 +26,6 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.arthas.tunnel.client.TunnelClient;
import com.taobao.arthas.common.AnsiLog;
import com.taobao.arthas.common.PidUtils;
import com.taobao.arthas.core.advisor.AdviceWeaver;
import com.taobao.arthas.core.advisor.TransformerManager;
import com.taobao.arthas.core.command.BuiltinCommandPack;
import com.taobao.arthas.core.config.BinderUtils;
@ -44,7 +43,6 @@ import com.taobao.arthas.core.shell.impl.ShellServerImpl;
import com.taobao.arthas.core.shell.term.impl.HttpTermServer;
import com.taobao.arthas.core.shell.term.impl.httptelnet.HttpTelnetTermServer;
import com.taobao.arthas.core.util.ArthasBanner;
import com.taobao.arthas.core.util.Constants;
import com.taobao.arthas.core.util.FileUtils;
import com.taobao.arthas.core.util.LogUtil;
import com.taobao.arthas.core.util.UserStatUtil;
@ -121,18 +119,10 @@ public class ArthasBootstrap {
Runtime.getRuntime().addShutdownHook(shutdown);
}
private static void initSpy() throws ClassNotFoundException, NoSuchMethodException {
Class<?> adviceWeaverClass = AdviceWeaver.class;
Method onBefore = adviceWeaverClass.getMethod(AdviceWeaver.ON_BEFORE, int.class, ClassLoader.class, String.class,
String.class, String.class, Object.class, Object[].class);
Method onReturn = adviceWeaverClass.getMethod(AdviceWeaver.ON_RETURN, Object.class);
Method onThrows = adviceWeaverClass.getMethod(AdviceWeaver.ON_THROWS, Throwable.class);
Method beforeInvoke = adviceWeaverClass.getMethod(AdviceWeaver.BEFORE_INVOKE, int.class, String.class, String.class, String.class, int.class);
Method afterInvoke = adviceWeaverClass.getMethod(AdviceWeaver.AFTER_INVOKE, int.class, String.class, String.class, String.class, int.class);
Method throwInvoke = adviceWeaverClass.getMethod(AdviceWeaver.THROW_INVOKE, int.class, String.class, String.class, String.class, int.class);
Spy.init(AdviceWeaver.class.getClassLoader(), onBefore, onReturn, onThrows, beforeInvoke, afterInvoke, throwInvoke);
private static void initSpy() {
// TODO init SpyImpl ?
}
private void initArthasEnvironment(String args) throws IOException {
if (arthasEnvironment == null) {
arthasEnvironment = new ArthasEnvironment();
@ -377,18 +367,17 @@ public class ArthasBootstrap {
}
/**
* 清除spy中对classloader的引用避免内存泄露
* 清除SpyAPI里的引用
*/
private void cleanUpSpyReference() {
SpyAPI.setNopSpy();
// AgentBootstrap.resetArthasClassLoader();
try {
// 从ArthasClassLoader中加载Spy
Class<?> spyClass = this.getClass().getClassLoader().loadClass(Constants.SPY_CLASSNAME);
Method agentDestroyMethod = spyClass.getMethod("destroy");
agentDestroyMethod.invoke(null);
} catch (ClassNotFoundException e) {
logger().error("Spy load failed from ArthasClassLoader, which should not happen", e);
} catch (Exception e) {
logger().error("Spy destroy failed: ", e);
Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass("com.taobao.arthas.agent3.AgentBootstrap");
Method method = clazz.getDeclaredMethod("resetArthasClassLoader");
method.invoke(null);
} catch (Throwable e) {
e.printStackTrace();
}
}

View File

@ -13,11 +13,6 @@ public class Constants {
private Constants() {
}
/**
* Spy的全类名
*/
public static final String SPY_CLASSNAME = "java.arthas.Spy";
/**
* 中断提示
*/

View File

@ -1,131 +0,0 @@
package java.arthas;
import java.lang.reflect.Method;
/**
* 间谍类<br/>
* 藏匿在各个ClassLoader中
* Created by vlinux on 15/8/23.
*/
public class Spy {
public static final String ON_BEFORE = "methodOnBegin";
public static final String ON_RETURN = "methodOnReturnEnd";
public static final String ON_THROWS = "methodOnThrowingEnd";
public static final String BEFORE_INVOKE = "methodOnInvokeBeforeTracing";
public static final String AFTER_INVOKE = "methodOnInvokeAfterTracing";
public static final String THROW_INVOKE = "methodOnInvokeThrowTracing";
// -- 各种Advice的钩子引用 --
public static volatile Method ON_BEFORE_METHOD;
public static volatile Method ON_RETURN_METHOD;
public static volatile Method ON_THROWS_METHOD;
public static volatile Method BEFORE_INVOKING_METHOD;
public static volatile Method AFTER_INVOKING_METHOD;
public static volatile Method THROW_INVOKING_METHOD;
/**
* arthas's classloader 引用
*/
public static volatile ClassLoader CLASSLOADER;
/**
* 代理重设方法
*/
public static volatile Method AGENT_RESET_METHOD;
/**
* 用于普通的间谍初始化
*/
public static void init(
ClassLoader classLoader,
Method onBeforeMethod,
Method onReturnMethod,
Method onThrowsMethod,
Method beforeInvokingMethod,
Method afterInvokingMethod,
Method throwInvokingMethod) {
CLASSLOADER = classLoader;
ON_BEFORE_METHOD = onBeforeMethod;
ON_RETURN_METHOD = onReturnMethod;
ON_THROWS_METHOD = onThrowsMethod;
BEFORE_INVOKING_METHOD = beforeInvokingMethod;
AFTER_INVOKING_METHOD = afterInvokingMethod;
THROW_INVOKING_METHOD = throwInvokingMethod;
}
/**
* Clean up the reference to com.taobao.arthas.agent.AgentLauncher$1
* to avoid classloader leak.
*/
public static void destroy() {
initEmptySpy();
// clear the reference to ArthasClassLoader in AgentLauncher
if (AGENT_RESET_METHOD != null) {
try {
AGENT_RESET_METHOD.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
}
AGENT_RESET_METHOD = null;
}
private static void initEmptySpy() {
try {
Class<?> adviceWeaverClass = Spy.class;
Method onBefore = adviceWeaverClass.getMethod(Spy.ON_BEFORE, int.class, ClassLoader.class, String.class,
String.class, String.class, Object.class, Object[].class);
Method onReturn = adviceWeaverClass.getMethod(Spy.ON_RETURN, Object.class);
Method onThrows = adviceWeaverClass.getMethod(Spy.ON_THROWS, Throwable.class);
Method beforeInvoke = adviceWeaverClass.getMethod(Spy.BEFORE_INVOKE, int.class, String.class, String.class,
String.class, int.class);
Method afterInvoke = adviceWeaverClass.getMethod(Spy.AFTER_INVOKE, int.class, String.class, String.class,
String.class, int.class);
Method throwInvoke = adviceWeaverClass.getMethod(Spy.THROW_INVOKE, int.class, String.class, String.class,
String.class, int.class);
Spy.init(null, onBefore, onReturn, onThrows, beforeInvoke, afterInvoke, throwInvoke);
} catch (Exception e) {
}
}
/**
* empty method
*
* @see com.taobao.arthas.core.advisor.AdviceWeaver#methodOnBegin(int,
* ClassLoader, String, String, String, Object, Object[])
* @param adviceId
* @param loader
* @param className
* @param methodName
* @param methodDesc
* @param target
* @param args
*/
public static void methodOnBegin(int adviceId, ClassLoader loader, String className, String methodName,
String methodDesc, Object target, Object[] args) {
}
/**
* empty method
*
* @see com.taobao.arthas.core.advisor.AdviceWeaver#methodOnReturnEnd(Object)
* @param returnObject
*/
public static void methodOnReturnEnd(Object returnObject) {
}
public static void methodOnThrowingEnd(Throwable throwable) {
}
public static void methodOnInvokeBeforeTracing(int adviceId, String owner, String name, String desc,
int lineNumber) {
}
public static void methodOnInvokeAfterTracing(int adviceId, String owner, String name, String desc,
int lineNumber) {
}
public static void methodOnInvokeThrowTracing(int adviceId, String owner, String name, String desc,
int lineNumber) {
}
}

View File

@ -21,7 +21,7 @@ package java.arthas;
*
*/
public class SpyAPI {
private static final AbstractSpy NOPSPY = new NopSpy();
private static volatile AbstractSpy spyInstance = new NopSpy();
public static AbstractSpy getSpy() {
@ -31,6 +31,10 @@ public class SpyAPI {
public static void setSpy(AbstractSpy spy) {
spyInstance = spy;
}
public static void setNopSpy() {
setSpy(NOPSPY);
}
public static void atEnter(Class<?> clazz, String methodInfo, Object target, Object[] args) {
spyInstance.atEnter(clazz, methodInfo, target, args);