【发布时间】:2015-01-21 19:34:03
【问题描述】:
是否有(首选便携式)方法来检查是否
JVM 已用特定的-javaagent?
我特别想知道 aspectj 加载时间编织器是否已加载。 (我试图在启动不正确的情况下提供有用的错误消息)。
【问题讨论】:
标签: java aspectj javaagents
是否有(首选便携式)方法来检查是否
JVM 已用特定的-javaagent?
我特别想知道 aspectj 加载时间编织器是否已加载。 (我试图在启动不正确的情况下提供有用的错误消息)。
【问题讨论】:
标签: java aspectj javaagents
以下代码显示
-javaagent:... JVM 参数的方法,Premain-Class: 中提到的类)是否已加载的方法。前者只是证明参数是在命令行中给出的,而不是真正找到并启动了代理。
后者只是证明编织器在类路径上可用,而不是它实际上是作为代理启动的。两者的结合应该让您对代理实际上处于活动状态充满信心。
package de.scrum_master.app;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
public class Application {
public static void main(String[] args) {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
for (String argument : arguments) {
if (argument.startsWith("-javaagent:"))
System.out.println(argument);
}
try {
Class.forName("org.aspectj.weaver.loadtime.Agent");
} catch (ClassNotFoundException e) {
System.err.println("WARNING: AspectJ weaving agent not loaded");
}
}
}
您还可能会发现问题Starting a Java agent after program start 及其一些答案很有帮助。
更新:
好的,这是我自己的解决方案和您的解决方案的组合,但即使织布工不可用,它也确实有效,这很重要,因为这是您首先要检查的:
public static boolean isAspectJAgentLoaded() {
try {
Class<?> agentClass = Class.forName("org.aspectj.weaver.loadtime.Agent");
Method method = agentClass.getMethod("getInstrumentation");
method.invoke(null);
} catch (Exception e) {
//System.out.println(e);
return false;
}
return true;
}
更新 2:
在与 OP bacar 讨论后,我决定提供一个不使用反射但捕获 NoClassDefError 的解决方案:
public static boolean isAspectJAgentLoaded() {
try {
org.aspectj.weaver.loadtime.Agent.getInstrumentation();
} catch (NoClassDefFoundError | UnsupportedOperationException e) {
System.out.println(e);
return false;
}
return true;
}
现在两种主要错误类型
org.aspectj.weaver.loadtime.Agent 不可用通过返回false在警告消息(在这个简单的示例中只是清楚说明问题所在的异常)已在控制台上打印出来来优雅地处理。
这两种情况可能的控制台输出是:
java.lang.UnsupportedOperationException: Java 5 was not started with preMain -javaagent for AspectJjava.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent【讨论】:
-javaagent:... 部分在命令行中被遗忘/省略,则可以帮助我动态附加编织代理。我创建了一个AspectJ bug ticket 以便在上游获得该功能。
我发现了以下作品(针对 1.8.4 进行了测试),尽管它依赖于未记录的 aspectjweaver 功能,因此可能无法跨版本运行。
public static boolean isAspectJAgentLoaded() {
try {
org.aspectj.weaver.loadtime.Agent.getInstrumentation();
return true;
} catch (UnsupportedOperationException e) {
return false;
}
}
解释:当aspectj作为代理加载时,JVM会调用org.aspectj.weaver.loadtime.Agent.premain(...)静态方法。这有一个我们可以测试的副作用。调用 getInstrumentation 要么抛出 UnsupportedOperationException(如果它没有被初始化为代理),或者如果它是成功返回。
【讨论】:
Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent。我宁愿推荐使用Class.forName(..),就像我在回答中所做的那样,然后(仅在成功的情况下)通过反射调用getInstrumentation()。查看我的答案的更新。
-javaagent 加载的 jar 是否可用于默认类加载器——你测试过你的提议吗? (如果您有自定义 ClassLoaders,我认为这两种解决方案的所有赌注都没有)
catch 子句。我认为让整个应用程序退出并在实用程序方法中出现未处理的错误是不好的,即使这个错误发生在您想要优雅处理的情况下。如果你把编织器放在类路径上,这并不意味着 LTW 处于活动状态,因为它仍然没有作为代理加载。在命令行上指定两次是违反直觉的。恕我直言,我的解决方案非常出色。
NoClassDefFoundError。