Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何插入由自定义类装入器装入的类?_Java_Classloader_Instrumentation_Javassist_Javaagents - Fatal编程技术网

Java 如何插入由自定义类装入器装入的类?

Java 如何插入由自定义类装入器装入的类?,java,classloader,instrumentation,javassist,javaagents,Java,Classloader,Instrumentation,Javassist,Javaagents,我试图修改几个类的字节码,这些类的打包jar文件不在类路径中——它们在给定URL的运行时由自定义ClassLoader加载。我尝试将java代理与ClassFileTransformer一起使用,希望拦截这些类,但失败了。类加载器是遗留项目的一部分,因此我无法直接对其进行更改 代理在AppClassLoader“本地”加载的类上运行良好,但忽略了自定义classloader加载的类 CustomClassLoader: public class CustomClassLoader ext

我试图修改几个类的字节码,这些类的打包jar文件不在类路径中——它们在给定URL的运行时由自定义
ClassLoader
加载。我尝试将
java代理
ClassFileTransformer
一起使用,希望拦截这些类,但失败了。类加载器是遗留项目的一部分,因此我无法直接对其进行更改

代理在AppClassLoader“本地”加载的类上运行良好,但忽略了自定义classloader加载的类

CustomClassLoader

    public class CustomClassLoader extends URLClassLoader {

    public CustomClassLoader(URL[] urls) {
        super(urls, CustomClassLoader.class.getClassLoader());
    }

    // violates parent-delegation pattern
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class<?> clazz = findLoadedClass(name);
            if (clazz == null) {
                try {
                    clazz = findClass(name);
                } catch (ClassNotFoundException e) {
                }

                if (clazz == null) {
                    clazz = getParent().loadClass(name);
                }
            }
            if (resolve) {
                resolveClass(clazz);
            }
            return clazz;
        }
    }
}
public class Agent
{
    public static void premain(String agentArgs, Instrumentation inst)
    {
        inst.addTransformer(new MyTransformer());
    }

}
我想出了一个解决办法,通过检测CustomClassLoader本身,调用instrumentation.redifineClasses(),但不知道如何将检测实例传递到CustomClassLoader实例中;我对指令插入/类加载还不熟悉,但仍然不太清楚它们的机制。 有什么帮助吗?谢谢

简单来说:

  • 在应用程序内部,创建一个自定义URLClassLoader,在运行时将一些jar文件加载到文件系统的其他位置
  • 实现一个java代理,转换类加载器加载的类,替换其中一个方法体或其他东西
  • 在应用程序内部,将类的实例分配给其接口,并调用其插入指令的方法
  • 使用-javaagent运行应用程序进行检查

  • 我假设您的类没有正确检测,因为您正在调用
    ClassPool.getDefault()
    ,它不包括自定义类装入器可见的类文件,而只包括系统类装入器可见的类文件。您从不注册
    classfileBuffer
    类文件

    另一种选择是,您可以尝试更容易访问instrumentation API的方法:

    new AgentBuilder.Default()
      .type(named("com.example.services.TargetService"))
      .transform((builder, type, loader) -> {
        builder.method(named("verify")).intercept(FixedValue.of(true));
      }).installOn(instrumentation);
    

    可以从
    agentmain
    premain
    方法调用上述代理。如果类在附件期间已经(可能)加载,您还可以禁用类文件格式更改并重新定义现有类。

    您是否尝试过使用没有依赖关系的简单代理?例如,尝试简单地调用System.out.println(className);在方法转换中,然后返回classfileBuffer。我尝试使用CustomClassLoader加载一个类,在我的console@NicolasFilotto问题解决了,谢谢,你让我想起了我和代理一起使用的工具。代理本身收到了类加载事件的通知,但是如果没有将外部url添加到其类路径中,检测工具将无法获取字节码。这是类池问题,请添加
    cp.appendClassPath(new LoaderClassPath(loader))和工程,真的谢谢你,和字节巴迪看起来很酷。如果我有足够的代表,我会投票。
    
    new AgentBuilder.Default()
      .type(named("com.example.services.TargetService"))
      .transform((builder, type, loader) -> {
        builder.method(named("verify")).intercept(FixedValue.of(true));
      }).installOn(instrumentation);