Java17升级后sun.net.SocksProxy非法访问错误求助
问题:Java 17升级后访问sun.net.SocksProxy触发IllegalAccessError
我的应用在Java 11环境运行正常,但升级到Java 17后出现以下错误:
2022-08-05 09:02:09.323 ERROR 1 --- [ ASYNC-182] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected exception occurred invoking async method: public void com.freeproxy.sdkservice.services.asyncProxyCheck.async.AsyncProxyCheck.asyncProxyCheck(java.lang.String,java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String) java.lang.IllegalAccessError: class com.freeproxy.sdkservice.services.asyncProxyCheck.async.AsyncProxyCheck (in unnamed module @0xd7b1517) cannot access class sun.net.SocksProxy (in module java.base) because module java.base does not export sun.net to unnamed module @0xd7b1517 at com.freeproxy.sdkservice.services.asyncProxyCheck.async.AsyncProxyCheck.socksProxyCheck(AsyncProxyCheck.groovy:130) ~[classes!/:na] at com.freeproxy.sdkservice.services.asyncProxyCheck.async.AsyncProxyCheck.asyncProxyCheck(AsyncProxyCheck.groovy:112) ~[classes!/:na] at com.freeproxy.sdkservice.services.asyncProxyCheck.async.AsyncProxyCheck$$FastClassBySpringCGLIB$$4cf6e456.invoke(<generated>) ~[classes!/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.3.20.jar!/:5.3.20] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
该错误在调用以下使用SocksProxy的方法时触发:
int socksProxyCheck(String proxyIp, int proxyPort, String url, int version, String proxyLogin = null, String proxyPassword = null) { try { URL webUrl = new URL(url) SocksProxy proxy = SocksProxy.create(new InetSocketAddress(proxyIp, proxyPort), version) if (proxyLogin && proxyPassword) { setAuthentication(proxyLogin, proxyPassword) } URLConnection con = (HttpURLConnection) webUrl.openConnection(proxy) con.setRequestMethod("GET") con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") con.setRequestProperty("Content-Language", "en-US") con.setConnectTimeout(5000) con.connect() int responseCode = con.responseCode con.disconnect() return responseCode } catch (e) { } return -1 }
我的gradle-wrapper.properties文件:
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists
build.gradle文件:
plugins { id 'org.springframework.boot' version '2.7.0' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'groovy' // id 'com.avast.gradle.docker-compose' version '0.7.1' } allprojects { apply plugin: 'groovy' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' group = 'com.free-proxy' sourceCompatibility = '17' targetCompatibility = '17' buildDir = '../build' configurations { compileOnly { extendsFrom annotationProcessor } } dependencies { // different dependencies go here } repositories { mavenCentral() } }
我推测是Java 17相对Java 11的配置变更导致的,求修复方案。
解决方案
问题根源
Java 9引入模块系统后,sun.net.SocksProxy属于java.base模块的内部非公开API。Java 11对内部API的访问限制较宽松,但Java 17严格执行了模块封装规则,禁止未命名模块(你的应用)访问java.base模块未对外导出的包,因此触发IllegalAccessError。
方法一:替换为Java标准API(推荐)
不要依赖内部API,改用Java标准库提供的Proxy类实现SOCKS代理功能,认证部分用Authenticator处理:
int socksProxyCheck(String proxyIp, int proxyPort, String url, int version, String proxyLogin = null, String proxyPassword = null) { try { URL webUrl = new URL(url) // 使用标准Proxy类创建SOCKS代理 Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(proxyIp, proxyPort)) // 处理代理认证(如果需要) if (proxyLogin != null && proxyPassword != null) { Authenticator originalAuthenticator = Authenticator.getDefault() Authenticator.setDefault(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(proxyLogin, proxyPassword.toCharArray()) } }) } URLConnection con = (HttpURLConnection) webUrl.openConnection(proxy) con.setRequestMethod("GET") con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") con.setRequestProperty("Content-Language", "en-US") con.setConnectTimeout(5000) con.connect() int responseCode = con.getResponseCode() con.disconnect() // 恢复默认Authenticator,避免影响其他请求 if (proxyLogin != null && proxyPassword != null) { Authenticator.setDefault(originalAuthenticator) } return responseCode } catch (Exception e) { e.printStackTrace() } return -1 }
方法二:添加JVM参数临时放宽限制(仅过渡用)
如果暂时无法重构代码,可以通过JVM参数强制让java.base模块导出sun.net包给未命名模块:
--add-exports java.base/sun.net=ALL-UNNAMED
在Spring Boot的Gradle配置中,可将参数添加到bootRun任务:
bootRun { jvmArgs = ['--add-exports', 'java.base/sun.net=ALL-UNNAMED'] }
注意:这只是临时方案,未来Java版本可能彻底移除这些内部API,最终仍需替换为标准API。
内容的提问来源于stack exchange,提问作者Oleksandr Popov
相关产品推荐
相关产品推荐

