From aea2ec25da8b76a1ad8aba4d3ec799498399cf43 Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Wed, 24 Jun 2020 17:59:02 +0800 Subject: [PATCH] Checking if arthas is started via SpyAPI --- .../arthas/agent332/AgentBootstrap.java | 20 ++++++++++++++- .../arthas/core/server/ArthasBootstrap.java | 13 +++++++++- spy/src/main/java/java/arthas/SpyAPI.java | 25 ++++++++++++++++--- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/agent/src/main/java/com/taobao/arthas/agent332/AgentBootstrap.java b/agent/src/main/java/com/taobao/arthas/agent332/AgentBootstrap.java index 311631fad..34e3c4bb0 100755 --- a/agent/src/main/java/com/taobao/arthas/agent332/AgentBootstrap.java +++ b/agent/src/main/java/com/taobao/arthas/agent332/AgentBootstrap.java @@ -1,5 +1,6 @@ package com.taobao.arthas.agent332; +import java.arthas.SpyAPI; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; @@ -50,7 +51,13 @@ public class AgentBootstrap { } } - // 全局持有classloader用于隔离 Arthas 实现 + /** + *
+     * 1. 全局持有classloader用于隔离 Arthas 实现,防止多次attach重复初始化
+     * 2. ClassLoader在arthas停止时会被reset
+     * 3. 如果ClassLoader一直没变,则 com.taobao.arthas.core.server.ArthasBootstrap#getInstance 返回结果一直是一样的
+     * 
+ */ private static volatile ClassLoader arthasClassLoader; public static void premain(String args, Instrumentation inst) { @@ -81,6 +88,17 @@ public class AgentBootstrap { } private static synchronized void main(String args, final Instrumentation inst) { + // 尝试判断arthas是否已在运行,如果是的话,直接就退出 + try { + Class.forName("java.arthas.SpyAPI"); // 加载不到会抛异常 + if (SpyAPI.isInited()) { + ps.println("Arthas server already stared, skip attach."); + ps.flush(); + return; + } + } catch (Throwable e) { + // ignore + } try { ps.println("Arthas server agent start..."); // 传递的args参数分两个部分:arthasCoreJar路径和agentArgs, 分别是Agent的JAR包路径和期望传递到服务端的参数 diff --git a/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java b/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java index af0372112..a92290e2f 100644 --- a/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java +++ b/core/src/main/java/com/taobao/arthas/core/server/ArthasBootstrap.java @@ -331,6 +331,12 @@ public class ArthasBootstrap { UserStatUtil.setStatUrl(configure.getStatUrl()); UserStatUtil.arthasStart(); + try { + SpyAPI.init(); + } catch (Throwable e) { + // ignore + } + logger().info("as-server started in {} ms", System.currentTimeMillis() - start); } catch (Throwable e) { logger().error("Error during bind to port " + configure.getTelnetPort(), e); @@ -442,7 +448,12 @@ public class ArthasBootstrap { * 清除SpyAPI里的引用 */ private void cleanUpSpyReference() { - SpyAPI.setNopSpy(); + try { + SpyAPI.setNopSpy(); + SpyAPI.destroy(); + } catch (Throwable e) { + // ignore + } // AgentBootstrap.resetArthasClassLoader(); try { Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.taobao.arthas.agent332.AgentBootstrap"); diff --git a/spy/src/main/java/java/arthas/SpyAPI.java b/spy/src/main/java/java/arthas/SpyAPI.java index 5de04962b..32762def9 100644 --- a/spy/src/main/java/java/arthas/SpyAPI.java +++ b/spy/src/main/java/java/arthas/SpyAPI.java @@ -21,8 +21,10 @@ package java.arthas; * */ public class SpyAPI { - private static final AbstractSpy NOPSPY = new NopSpy(); - private static volatile AbstractSpy spyInstance = new NopSpy(); + public static final AbstractSpy NOPSPY = new NopSpy(); + private static volatile AbstractSpy spyInstance = NOPSPY; + + public static volatile boolean INITED; public static AbstractSpy getSpy() { return spyInstance; @@ -31,11 +33,28 @@ public class SpyAPI { public static void setSpy(AbstractSpy spy) { spyInstance = spy; } - + public static void setNopSpy() { setSpy(NOPSPY); } + public static boolean isNopSpy() { + return NOPSPY == spyInstance; + } + + public static void init() { + INITED = true; + } + + public static boolean isInited() { + return INITED; + } + + public static void destroy() { + setNopSpy(); + INITED = false; + } + public static void atEnter(Class clazz, String methodInfo, Object target, Object[] args) { spyInstance.atEnter(clazz, methodInfo, target, args); }