Java 17无法拦截java.net.HttpURLConnection方法的解决方案咨询
解决方案:Java 17下用ByteBuddy拦截HttpURLConnection.connect()
问题根源
Java 17的模块系统(JPMS)限制了对核心模块内部类的访问,且ByteBuddy旧版手动注入方式无法适配模块权限;同时java.net.HttpURLConnection是抽象类,实际执行connect()逻辑的是其实现类sun.net.www.protocol.http.HttpURLConnection,直接拦截抽象类方法不会生效。
修改步骤与代码
1. 适配模块权限与ByteBuddy API
使用ByteBuddy内置的bootstrap注入策略自动处理拦截器的类加载权限,修正transform方法参数以适配Java 17编译要求,并指定拦截实际实现类。
2. 修改后的完整代码
package com.bytebuddy.bytebuddydemo.test; import net.bytebuddy.agent.ByteBuddyAgent; import net.bytebuddy.agent.builder.AgentBuilder; 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.lang.instrument.Instrumentation; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; 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()); urlConnection.connect(); System.out.println(urlConnection.getResponseCode()); } public static void premain(String arg, Instrumentation instrumentation) { new AgentBuilder.Default() .ignore(ElementMatchers.nameStartsWith("net.bytebuddy.")) // 启用重转换,支持修改已加载的类 .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) // 自动处理bootstrap类加载器下的注入权限 .with(AgentBuilder.InitializationStrategy.ForBootstrapInjection.INSTANCE) // 拦截实际实现类 .type(ElementMatchers.named("sun.net.www.protocol.http.HttpURLConnection")) // 补充protectionDomain参数适配Java 17编译要求 .transform((builder, typeDescription, classLoader, module, protectionDomain) -> 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 connect() method!"); System.out.println("Method details: " + method); zuper.call(); } } }
3. 运行所需JVM参数
Java 17下需添加以下参数开放核心模块访问权限:
--add-opens java.base/sun.net.www.protocol.http=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
关键修改说明
- 拦截实际实现类:替换原匹配规则为
sun.net.www.protocol.http.HttpURLConnection,确保拦截到真正执行逻辑的方法。 - 自动bootstrap注入:移除手动
ClassInjector代码,改用ByteBuddy内置策略,自动处理模块环境下的类注入权限问题。 - 适配编译要求:补充
protectionDomain参数,满足Java 17对AgentBuilder.transform方法的参数要求。 - 启用重转换:添加重转换策略,保证已加载的目标类可以被修改。
内容的提问来源于stack exchange,提问作者Tejas Soneri
相关产品推荐
相关产品推荐

