使用Java代理将类添加到类路径 [英] Adding a class to the class path with a Java Agent

查看:134
本文介绍了使用Java代理将类添加到类路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Java Agent和Javassist向某些JDK类添加一些日志记录。本质上,当系统加载一些TLS类时,Javassist将向它们添加一些附加的字节码来帮助我调试一些连接问题。

I'm using a Java Agent and Javassist to add some logging to some JDK classes. Essentially when the system loads some TLS classes, Javassist will add some additional bytecode to them to help me debug some connection problems.

这是问题所在,因为该类已包含在其中代理jar:

Here's the problem, given this class is included in the agent jar:

package com.something.myagent;
public class MyAgentPrinter {
    public static final void sayHello() {
        System.out.println("Hello!");
    }
}

在我的代理的transform方法中,假设我尝试使用javassist调用该类:

In my agent's transform method, let's say I tried to invoke that class using javassist:

// this is only called for sun.security.ssl.Handshaker
ClassPool cp = getClassPool(classfileBuffer, className);
CtClass cc = cp.get(className);
CtMethod declaredMethod = cc.getDeclaredMethod("calculateKeys");
declaredMethod.insertAfter("com.something.myagent.MyAgentPrinter.sayHello();");
cc.freeze();
return cc.toBytecode();

您认为这行得通,但我却得到了:

You think that would work, but instead I get this:

java.lang.NoClassDefFoundError: com/something/myagent/MyAgentPrinter
    at sun.security.ssl.Handshaker.printLogLine(Handshaker.java)
    at sun.security.ssl.Handshaker.calculateKeys(Handshaker.java:1160)
    at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:292)

是否可以将该类[ MyAgentPrinter ]添加到应用程序的类路径中?

Is there any way to add that class [MyAgentPrinter] to the application's class path?

推荐答案

您的Agent的jar文件已添加到类路径中,如 java.lang.instrument 软件包文档

Your Agent’s jar file is already added to the class path, as specified by the java.lang.instrument package documentation:


代理类将由系统类加载器加载(请参见 ClassLoader.getSystemClassLoader )。这是类加载器,通常加载包含应用程序 main 方法的类。 premain 方法将与应用程序 main 方法在相同的安全性和类加载器规则下运行。

The agent class will be loaded by the system class loader (see ClassLoader.getSystemClassLoader). This is the class loader which typically loads the class containing the application main method. The premain methods will be run under the same security and classloader rules as the application main method.

这就是Javassist在转换字节码时可以找到Agent的类的原因。

This is the reason why Javassist can find the Agent’s classes when you are transforming the byte code.

问题似乎是您正在转换 sun。** 类,该类很可能由引导加载程序或扩展加载程序加载。标准的类加载委托是

应用程序加载器→扩展加载器→引导加载程序,因此应用程序加载器可用的类不适用于扩展程序或引导加载程序。

The problem seems to be that you are transforming a sun.** class which is likely loaded by the bootstrap loader or extension loader. The standard class loading delegation is
application loader → extension loader → bootstrap loader, so classes available to the application loader are not available to classes loaded by the extension or bootstrap loader.

因此,要使它们可用于所有类,必须将代理程序的类添加到引导加载程序:

So, to make them available to all classes, you have to add the Agent’s classes to the bootstrap loader:

public class MyAgent {
    public static void premain(String agentArgs, Instrumentation inst) throws IOException {
        JarURLConnection connection = (JarURLConnection)
            MyAgent.class.getResource("MyAgent.class").openConnection();
        inst.appendToBootstrapClassLoaderSearch(connection.getJarFile());

        // proceed
    }
}

在执行任何其他操作之前,即在加载要提供给检测代码的类之前,请务必执行此操作。这意味着Agent类本身,即包含 premain 方法的类无法被检测代码访问。 Agent类也不应直接引用 MyAgentPrinter 以避免意外的提前加载。

It’s critical to do this before any other action, i.e. before the classes you want to make available to instrumented code have been loaded. This implies that the Agent class itself, i.e. the class containing the premain method can not get accessed by the instrumented code. The Agent class also shouldn’t have direct references to MyAgentPrinter to avoid unintended early loading.

一种更可靠的方法要将 Boot-Class-Path 条目添加到代理jar的清单中,请参见软件包文档的清单属性部分,以便在代理启动之前添加条目。但是,然后jar文件的名称一定不能更改。

A more reliable way is to add a Boot-Class-Path entry to the Agent jar’s manifest, see the "Manifest Attributes" section of the package documentation, so that the entry gets added before the Agent starts. But then, the name of the jar file must not change afterwards.

这篇关于使用Java代理将类添加到类路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆