无法拦截Java 17中java.net.HttpURLConnection类的方法

问题描述 投票:0回答:1

我想拦截java.net.HttpURLConnection的connect()方法。为此,我正在使用下面提供的代码。提供的代码拦截 Java 8 中 HttpURLConnection 类的 connect 方法。但是,当尝试使用 Java 17 运行相同的代码时,会导致下面提供的错误。 请提供任何解决方案或建议。

代码:

package com.bytebuddy.bytebuddydemo.test;

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;

import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.Collections;
import java.util.concurrent.Callable;

public class Test {
    public static void main(String[] args) throws Exception {
        premain(null, ByteBuddyAgent.install());
        HttpURLConnection urlConnection = (HttpURLConnection) new URL("http://www.google.com").openConnection();
        System.out.println(urlConnection.getRequestMethod());
        System.out.println(urlConnection.getResponseCode());
    }

    public static void premain(String arg, Instrumentation instrumentation) throws Exception {
        File tempDirectory = Files.createTempDirectory("tmp").toFile();
        ClassInjector.UsingInstrumentation
                .of(tempDirectory, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, instrumentation)
                .inject(Collections.singletonMap(new TypeDescription.ForLoadedType(MyInterceptor.class),
                        ClassFileLocator.ForClassLoader.read(MyInterceptor.class)));
        new AgentBuilder.Default().ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
                .with(new AgentBuilder.InjectionStrategy.UsingInstrumentation(instrumentation, tempDirectory))
                .type(ElementMatchers.nameEndsWith(".HttpURLConnection"))
                .transform((builder, typeDescription, classLoader, module) -> builder
                        .method(ElementMatchers.named("connect")).intercept(MethodDelegation.to(MyInterceptor.class)))
                .installOn(instrumentation);
    }

    public static class MyInterceptor {
        public static void intercept(@SuperCall Callable<?> zuper, @Origin Method method) throws Exception {
            System.out.println("Intercepted!");
            System.out.println("method :: !" + method);
            zuper.call();

        }
    }
}

错误:

Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/sun.net.www.protocol.http.Handler.openConnection(Handler.java:62)
at java.base/sun.net.www.protocol.http.Handler.openConnection(Handler.java:57)
at java.base/java.net.URL.openConnection(URL.java:1094)
at com.JavaAgent.Agent.Test.main(Test.java:26)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.net.www.protocol.http.HttpURLConnection.(HttpURLConnection.java:435)
... 4 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at net.bytebuddy.dynamic.Nexus.initialize(Nexus.java:143)
... 9 more
Caused by: java.lang.IllegalStateException: Cannot load injected class
at net.bytebuddy.dynamic.loading.ClassInjector$UsingInstrumentation.injectRaw(ClassInjector.java:2498)
at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:118)
at net.bytebuddy.agent.builder.AgentBuilder$InitializationStrategy$SelfInjection$Dispatcher$InjectingInitializer.onLoad(AgentBuilder.java:3855)
... 14 more
Caused by: java.lang.ClassNotFoundException: sun/net/www/protocol/http/HttpURLConnection$auxiliary$vcxnSSGw
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingInstrumentation.injectRaw(ClassInjector.java:2487)
... 16 more

在Java 17中执行提供的代码时,transform方法出现编译错误,表明它需要五个参数。为了解决此问题,将缺少的参数(protectionDomain)添加到方法签名中,以允许成功编译。然而,在运行时,程序会抛出异常。

java httpurlconnection open-telemetry byte-buddy javaagents
1个回答
0
投票

这个 GitHub Gist 复制答案,因此可以将问题标记为已接受:

package net.bytebuddy;

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.util.Collections;
import java.util.concurrent.Callable;

import static net.bytebuddy.matcher.ElementMatchers.none;

/**
 * Inspired by <a href="https://github.com/apache/skywalking">Apache SkyWalking</a>, specifically
 * <a href="https://github.com/apache/skywalking/blob/bc64c6a12770031478d29e2f19004796584374c9/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java">
 * this class</a>. Discussed in <a href="https://github.com/raphw/byte-buddy/issues/697">Byte Buddy issue #697</a>.
 * <p>
 * Successfully tested on JDKs 8 to 21. Should print:
 * <pre>
 * Intercepted!
 * GET
 * </pre>
 */
public class BootstrapAgent {
  public static void main(String[] args) throws Exception {
    premain(null, ByteBuddyAgent.install());
    Object urlConnection = new URL("http://www.google.com").openConnection();
    System.out.println(urlConnection.getClass().getMethod("getRequestMethod").invoke(urlConnection));
  }

  public static void premain(String arg, Instrumentation instrumentation) throws Exception {
    ClassInjector.UsingUnsafe.Factory factory = ClassInjector.UsingUnsafe.Factory.resolve(instrumentation);
    factory.make(null, null).injectRaw(
      Collections.singletonMap(
        MyInterceptor.class.getName(),
        ClassFileLocator.ForClassLoader.read(MyInterceptor.class)
      )
    );
    AgentBuilder agentBuilder = new AgentBuilder.Default();
    agentBuilder = agentBuilder.with(new AgentBuilder.InjectionStrategy.UsingUnsafe.OfFactory(factory));
    agentBuilder
      .ignore(none())
      .assureReadEdgeFromAndTo(instrumentation, Class.forName("java.net.HttpURLConnection"))
      .assureReadEdgeFromAndTo(instrumentation, MyInterceptor.class)
      .ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
      .type(ElementMatchers.nameContains("HttpURLConnection"))
      .transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
        .method(ElementMatchers.named("getRequestMethod"))
        .intercept(MethodDelegation.to(MyInterceptor.class))
      )
      .installOn(instrumentation);
  }

  public static class MyInterceptor {
    public static String intercept(@SuperCall Callable<String> zuper) throws Exception {
      System.out.println("Intercepted!");
      return zuper.call();
    }
  }
}

JDoodle上尝试一下。

© www.soinside.com 2019 - 2024. All rights reserved.