对于vmlens (轻量级Java竞争条件捕获器),我们使用Java代理来跟踪字段访问。 这是我们学习的实现此类代理的经验教训。
开始
使用“ static public static void premain(String args,Instrumentation inst)”方法创建一个代理类。 将该类放入一个jar文件中,其中包含指向Agent类的清单。 premain方法将在应用程序的main方法之前调用。
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.2
Created-By: 1.8.0_05-b13 (Oracle Corporation)
Built-By: Thomas Krieger
Implementation-Vendor: Anarsoft
Implementation-Title: VMLens Agent
Implementation-Version: 2.0.0.201511181111
Can-Retransform-Classes: true
Premain-Class: com.anarsoft.trace.agent.Agent
Boot-Class-Path: agent_bootstrap.jar
来自vmlens的MANIFEST.MF文件。
类加载器魔术第1部分
代理类将由系统类加载器加载。 但是我们必须避免代理和应用程序使用的类之间的版本冲突。 尤其是代理中使用的框架对于应用程序类应该不可见。 因此,我们使用专用的URLClassLoader来加载所有其他代理类:
// remember the currently used classloader
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();// Create and set a special URLClassLoader
URLClassLoader classloader = new URLClassLoader(urlList.toArray(new URL[]{}) , null );
Thread.currentThread().setContextClassLoader(classloader);// Load and execute the agent
String agentName = "com.anarsoft.trace.agent.runtime.AgentRuntimeImpl";
AgentRuntime agentRuntime = (AgentRuntime) classloader.loadClass(agentName).newInstance();// reset the classloader
Thread.currentThread().setContextClassLoader(contextClassLoader);
类加载器魔术第2部分
现在,当访问字段时,我们使用asm添加我们的静态回调方法。 为了确保这些类在所有其他类中可见,它们必须由引导类加载器加载。 为此,它们必须位于java包中,并且包含它们的jar必须位于引导类路径中。
package java.anarsoft.trace.agent.bootstrap.callback;public class FieldAccessCallback {public static void getStaticField(int field,int methodId) {}}
vmlens的回调类。 它必须在java包命名空间中才能在所有类中可见。
Boot-Class-Path: agent_bootstrap.jar
vmlens的MANIFEST.MF文件中的引导类路径条目。
VMLens是一种轻量级的Java竞争条件捕获器,是作为Java代理构建的。 我们知道,编写Java代理可能是一件棘手的事情。 因此,如果您有任何问题,请在下面的评论中提问。
翻译自: https://www.javacodegeeks.com/2015/12/write-java-agent.html