我是java代理的新手.我创建了一个简单的HotswapAgent类(从Play!Framework中嗅探):
public class HotswapAgent {
static Instrumentation instrumentation;
public static boolean enabled = false;
public static void premain(String agentArgs, Instrumentation instrumentation)
{
HotswapAgent.instrumentation = instrumentation;
HotswapAgent.enabled = true;
}
public static void reload(ClassDefinition... definitions)
throws UnmodifiableClassException, ClassNotFoundException
{
instrumentation.redefineClasses(definitions);
}
}
Run Code Online (Sandbox Code Playgroud)
有了这个清单:
Manifest-Version: 1.0
Premain-Class: path.to.HotswapAgent
Can-Redefine-Classes: true
Run Code Online (Sandbox Code Playgroud)
我尝试以这种方式重新加载一个新的类定义:
CtClass modelClass = ....
...
byte [] bcode = modelClass.toBytecode();
Class c = modelClass.toClass();
modelClass.defrost();
ClassDefinition cdef = new ClassDefinition(c, bcode);
HotswapAgent.reload(cdef);
Run Code Online (Sandbox Code Playgroud)
所有这些类都在一个jar中,最后我得到了这个错误(在reload()调用时):
redefineClasses is not supported in this environment
Run Code Online (Sandbox Code Playgroud)
但是在Manifest中宣布了 …
从Java 5开始,可以选择将Java代理添加到类加载器.
你有没有写过任何特工?你使用过任何特工吗?Agent的有趣用途是什么?
我使用 gradle (v1.10) 中的应用程序插件来打包和运行我的应用程序。
所以,现在我需要使用方面(aspectj),并且我不想使用方面j编译器(ajc)。
是否可以调整 gradle 应用程序运行脚本,以便我的应用程序可以通过加载时编织来运行?比如提供 jvm 选项:
-javaagent:_path_to_aspectj_weaver.jar
我创建了一个java应用程序并使用该应用程序初始化java.util.Logger并运行该应用程序,就像-javaagent使用jboss AS 7服务器一样IllegalStateException(我使用的是eclipse IDE).这是我的logger初始化代码
static public void setup() throws IOException {
// Get the global logger to configure it
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
logger.setLevel(Level.INFO);
fileTxt = new FileHandler("C:/Users/abc/Desktop/ATAGENT/Logging.txt");
fileHTML = new FileHandler("C:/Users/abc/Desktop/ATAGENT/Logging.html");
// create txt Formatter
formatterTxt = new SimpleFormatter();
fileTxt.setFormatter(formatterTxt);
logger.addHandler(fileTxt);
// create HTML Formatter
formatterHTML = new BMITHtmlFormatter();
fileHTML.setFormatter(formatterHTML);
logger.addHandler(fileHTML);
}
当我创建-javaagentjar附加上面的代码行并使用jboss as7服务器运行时,我得到以下异常
WARNING: Failed to load the specified log manager class org.jboss.logmanager.LogManager
Exception in thread "main" java.lang.ExceptionInInitializerError
at org.jboss.as.server.Main.main(Main.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native …Run Code Online (Sandbox Code Playgroud) 我知道 Spring 避免使用-javaagentvm 选项来使其 AspectJ 加载时间编织工作,而是依赖类加载器来启动代理。
我认为 Java 规范规定使用 Java 代理的唯一方法是通过-javaagentvm 选项。
我错了吗?有人可以将我引导到官方 Java 规范/文档来澄清我的审讯吗?
要告诉 JVM 在 Jar 文件的主类之前调用 Java Instrumentation 代理,通常必须使用命令选项调用它:
java -javaagent:agent.jar program.jar
Run Code Online (Sandbox Code Playgroud)
每次都必须输入这个非常不方便,那么有没有办法在program.jar清单中指定代理?
# program.jar/META-INF/MANIFEST.MF
...
Java-Agent: agent.jar
Run Code Online (Sandbox Code Playgroud) 我正在为我的 Spring Boot 应用程序使用 javaagent,目前我正在通过
java -javaagent:agent.jar -jar app.jar
Run Code Online (Sandbox Code Playgroud)
我的项目是一个 gradle 项目,我想将 agent.jar 嵌入到 app.jar 中,以便我可以将它作为
java -javaagent:app.jar -jar app.jar
Run Code Online (Sandbox Code Playgroud)
它可以通过这里提到的引导 maven 插件来完成 - https://jeroendruwe.be/spring-boot-and-new-relic/但引导 gradle 插件别无选择。我找到的最接近的是这个 - https://jdpgrailsdev.github.io/blog/2014/04/08/spring_boot_gradle_newrelic.html,但它没有按预期嵌入 jar。
无论如何它可以通过gradle完成吗?
这个问题花了我太长时间才弄清楚。
我试图通过在运行/调试配置中配置以下 VM 选项来配置 Java 代理以在 IntelliJ 中执行测试:
-javaagent:~/.m2/repository/org/springframework/spring-instrument/5.0.4.RELEASE/spring-instrument-5.0.4.RELEASE.jar
Run Code Online (Sandbox Code Playgroud)
它一直失败
Error opening zip file or JAR manifest missing : ~/.m2/repository/org/springframework/spring-instrument/5.0.4.RELEASE/spring-instrument-5.0.4.RELEASE.jar
Error occurred during initialization of VM
agent library failed to init: instrument
Run Code Online (Sandbox Code Playgroud)
类似的问题讨论了实际损坏的 jar 文件或路径中的空格,这不适用于我的情况。
我正在使用 Java 代理 (Agent.class) 以包含对 Agent 类的调用的方式转换程序 (Program.class) 中的方法。
public Program.getMultiplier()F:
ALOAD 1
ALOAD 2
FDIV
+ INVOKESTATIC Agent.getCustomMultiplier(F)F
FRETURN
Run Code Online (Sandbox Code Playgroud)
我检查了代理类和程序类的类加载器及其父类,它们的层次结构如下所示:
AppClassLoader<- PlatformClassLoader<-nullURLClassLoader<- PlatformClassLoader<-null当程序执行添加的INVOKESTATIC指令时,它会抛出 ClassNotFoundException - 它无法找到 Agent 类,因为它是由不同的类加载器加载的。
作为临时解决方案,我尝试强制AppClassLoader成为URLClassLoaderwith 反射的父级,它适用于较旧的 Java 版本,但自 Java 12 以来已被删除。
有没有更可靠的方法来确保我的代理类在任何类加载器中都是可见的?
javaagents ×10
java ×6
aspectj ×2
classloader ×2
jvm ×2
eclipse ×1
gradle ×1
jar ×1
jboss7.x ×1
logging ×1
macos ×1
manifest ×1
spring-aop ×1
spring-boot ×1