在 JDK 11.0.11 上使用 '-Djava.system.class.loader' 时出现异常,如果 class 加载程序在已签名的 JAR 中
Exception when using '-Djava.system.class.loader' on JDK 11.0.11, if class loader is in signed JAR
我在 start/run Java Java 工具套件 4.11(基于 Eclipse 2021-06)中使用 Spring 工具套件中的 AspectJ Load-Time-Weaving 应用程序时遇到问题=] 11.0.11 运行时(使用 AdoptOpenJDK 11.0.11.9-hotspot 或 Oracle JDK build 11.0.11+9-LTS-194 或 Zulu11.48+21-CA(build 11.0.11 +9-LTS) 在 Windows 上 10) 当访问 javax.net.ssl.SSLContext
时。对于较旧的 Java 11 版本,不会出现此问题。
我已将问题简化为一个小应用程序:
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException {
String cp = System.getProperty("java.class.path");
System.err.println(cp);
String cn = System.getProperty("java.system.class.loader");
System.err.println(cn);
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
}
}
该应用程序在 Eclipse 中使用 AspectJ LTW 启动配置启动。
我得到的输出和异常是这样的:
D:\sts-4.11.0.RELEASE\plugins\org.aspectj.weaver_1.9.6.202103162301.jar;D:\sts-4.11.0.RELEASE\plugins\org.aspectj.runtime_1.9.6.202103162301.jar
org.aspectj.weaver.loadtime.WeavingURLClassLoader
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class sun.security.jca.ProviderConfig$ProviderLoader
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:248)
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:242)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:242)
at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:222)
at java.base/sun.security.jca.ProviderList.getProvider(ProviderList.java:266)
at java.base/sun.security.jca.ProviderList$ServiceList.tryGet(ProviderList.java:511)
at java.base/sun.security.jca.ProviderList$ServiceList.hasNext(ProviderList.java:565)
at java.base/java.security.Signature.getInstance(Signature.java:266)
at java.base/sun.security.ssl.JsseJce.getSignature(JsseJce.java:202)
at java.base/sun.security.ssl.JsseJce$EcAvailability.<clinit>(JsseJce.java:394)
at java.base/sun.security.ssl.JsseJce.isEcAvailable(JsseJce.java:175)
at java.base/sun.security.ssl.CipherSuite$KeyExchange.isAvailable(CipherSuite.java:1079)
at java.base/sun.security.ssl.CipherSuite.isAvailable(CipherSuite.java:941)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableCipherSuites(SSLContextImpl.java:384)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(SSLContextImpl.java:347)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:580)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1918)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.pmd.bug.Main.main(Main.java:18)
这是我使用 VM 参数 "-Djava.security.debug="jca"
:
启用安全调试日志时的完整输出
ProviderList: provider configuration: [SUN, SunRsaSign, SunEC, SunJSSE, SunJCE, SunJGSS, SunSASL, XMLDSig, SunPCSC, JdkLDAP, JdkSASL, SunMSCAPI, SunPKCS11]
ProviderList: config configuration: null
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Disabling ThreadLocal providers
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Loading all providers
java.lang.Exception: Debug Info. Call trace:
at java.base/sun.security.jca.ProviderList.loadAll(ProviderList.java:311)
at java.base/sun.security.jca.ProviderList.removeInvalid(ProviderList.java:332)
at java.base/sun.security.jca.Providers.getFullProviderList(Providers.java:165)
at java.base/java.security.Security.getProviders(Security.java:457)
at java.base/sun.security.x509.AlgorithmId.computeOidTable(AlgorithmId.java:637)
at java.base/sun.security.x509.AlgorithmId.oidTable(AlgorithmId.java:627)
at java.base/sun.security.x509.AlgorithmId.algOID(AlgorithmId.java:609)
at java.base/sun.security.x509.AlgorithmId.get(AlgorithmId.java:441)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:380)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.pkcs.SignerInfo.getTimestamp(SignerInfo.java:545)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:318)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:283)
at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:259)
at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)
at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:230)
at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:759)
at java.base/java.util.jar.JarFile.ensureInitialization(JarFile.java:1038)
at java.base/java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
at java.base/jdk.internal.loader.URLClassPath$JarLoader.getManifest(URLClassPath.java:870)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:786)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1976)
at java.base/java.lang.System.initPhase3(System.java:2074)
ProviderConfig: Loading provider SunEC
ProviderConfig: Error loading provider SunEC
java.lang.ExceptionInInitializerError
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:248)
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:242)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:242)
at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:222)
at java.base/sun.security.jca.ProviderList.loadAll(ProviderList.java:315)
at java.base/sun.security.jca.ProviderList.removeInvalid(ProviderList.java:332)
at java.base/sun.security.jca.Providers.getFullProviderList(Providers.java:165)
at java.base/java.security.Security.getProviders(Security.java:457)
at java.base/sun.security.x509.AlgorithmId.computeOidTable(AlgorithmId.java:637)
at java.base/sun.security.x509.AlgorithmId.oidTable(AlgorithmId.java:627)
at java.base/sun.security.x509.AlgorithmId.algOID(AlgorithmId.java:609)
at java.base/sun.security.x509.AlgorithmId.get(AlgorithmId.java:441)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:380)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.pkcs.SignerInfo.getTimestamp(SignerInfo.java:545)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:318)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:283)
at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:259)
at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)
at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:230)
at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:759)
at java.base/java.util.jar.JarFile.ensureInitialization(JarFile.java:1038)
at java.base/java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
at java.base/jdk.internal.loader.URLClassPath$JarLoader.getManifest(URLClassPath.java:870)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:786)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1976)
at java.base/java.lang.System.initPhase3(System.java:2074)
Caused by: java.lang.IllegalStateException: getSystemClassLoader cannot be called during the system class loader instantiation
at java.base/java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1932)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<init>(ProviderConfig.java:323)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<clinit>(ProviderConfig.java:313)
... 38 more
ProviderList: Disabling ThreadLocal providers
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Disabling ThreadLocal providers
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Disabling ThreadLocal providers
D:\sts-4.11.0.RELEASE\plugins\org.aspectj.weaver_1.9.6.202103162301.jar;D:\sts-4.11.0.RELEASE\plugins\org.aspectj.runtime_1.9.6.202103162301.jar
org.aspectj.weaver.loadtime.WeavingURLClassLoader
Hello World!
ProviderConfig: Loading provider SunJGSS
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class sun.security.jca.ProviderConfig$ProviderLoader
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:248)
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:242)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:242)
at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:222)
at java.base/sun.security.jca.ProviderList.getProvider(ProviderList.java:266)
at java.base/sun.security.jca.ProviderList$ServiceList.tryGet(ProviderList.java:511)
at java.base/sun.security.jca.ProviderList$ServiceList.hasNext(ProviderList.java:565)
at java.base/java.security.Signature.getInstance(Signature.java:266)
at java.base/sun.security.ssl.JsseJce.getSignature(JsseJce.java:202)
at java.base/sun.security.ssl.JsseJce$EcAvailability.<clinit>(JsseJce.java:394)
at java.base/sun.security.ssl.JsseJce.isEcAvailable(JsseJce.java:175)
at java.base/sun.security.ssl.CipherSuite$KeyExchange.isAvailable(CipherSuite.java:1079)
at java.base/sun.security.ssl.CipherSuite.isAvailable(CipherSuite.java:941)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableCipherSuites(SSLContextImpl.java:384)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(SSLContextImpl.java:347)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:580)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1918)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.pmd.bug.Main.main(Main.java:18)
在我看来,当系统 class 加载程序在 Classloader#initSystemClassLoader
中初始化为 org.aspectj.weaver.loadtime.WeavingURLClassLoader
时,一些步骤之后会以某种方式触发所有安全提供程序的加载,而这又需要访问系统 class 加载程序(尚未完全初始化)。
这导致日志的这一部分:
Caused by: java.lang.IllegalStateException: getSystemClassLoader cannot be called during the system class loader instantiation
at java.base/java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1932)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<init>(ProviderConfig.java:323)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<clinit>(ProviderConfig.java:313)
稍后在应用程序中调用 SSLContext.getInstance("TLS"),再次需要 sun.security.jca.ProviderConfig$ProviderLoader,但这次因 NoClassDefFoundError 而失败。
你觉得我的分析正确吗?
这是 OpenJDK 11.0.11 中的(潜在)错误吗?
这个问题有解决办法吗?
更新 (06.07.21):
I found out 如何查看 Eclipse 启动配置产生的完整命令行调用。这是:
C:\Programme\Java\jdk-11.0.11.9-hotspot\bin\javaw.exe -Djava.security.debug=jca -Djava.system.class.loader=org.aspectj.weaver.loadtime.WeavingURLClassLoader -Daj.class.path=D:\workspace\sts490\edrewemaster\example-demo\target\classes;D:\workspace\sts490\edrewemaster\example-demo\target\test-classes;D:\repo\org\aspectj\aspectjrt.9.6\aspectjrt-1.9.6.jar;D:\workspace\sts490\edrewemaster\example-demo\target\classes -Dfile.encoding=Cp1252 -classpath D:\sts-4.11.0.RELEASE\plugins\org.aspectj.weaver_1.9.6.202103162301.jar;D:\sts-4.11.0.RELEASE\plugins\org.aspectj.runtime_1.9.6.202103162301.jar org.pmd.bug.Main
当我像这样从命令行 运行 时(使用 java 而不是 javaw),我也得到了异常。当我使用像
这样的旧 Java 版本 (11.0.10) 时
C:\Programme\Java.0.10_9_adopt\jdk-11.0.10+9\bin\java ...
有效。
所以 Eclipse 似乎取代了 LTW 的系统 class 加载程序。有没有办法告诉 Eclipse 将 LTW 与 java 代理解决方案一起使用?也许这可以解决这个问题?
我想我找到了解决方法:不要使用类型为“AspectJ Load-Time Weaving Application”的 Eclipse 启动配置,而是使用普通的 Java 应用程序启动配置并通过“-javaagent”标志启用 LTW,例如
-javaagent:D:\repo\org\aspectj\aspectjweaver.9.6\aspectjweaver-1.9.6.jar
这对我有用。
我做了几个实验,发现问题所在
- 与AspectJ完全无关,
- 一般来说与Java代理完全无关,
- 发生当且仅当
使用-Djava.system.class.loader
和
- 有问题的系统 class 加载程序在签名的 JAR 中找到并且
- 该应用程序在 JDK 11.0.11 上运行(不是 11.0.10 或我测试过的任何其他 JDK 9-16)。
一旦我从 META-INF
目录中删除 JAR 签名,它也适用于 JDK 11.0.11。 IMO,这是 JDK 中的回归错误,应该修复。这是一个最小的测试用例:
package org.acme.app;
public class Main {
public static void main(String[] args) {}
}
package org.acme.loader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class CustomClassLoader extends ClassLoader {
public CustomClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassFromFile(String fileName) {
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream(fileName.replace('.', File.separatorChar) + ".class");
byte[] buffer;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
while ((nextValue = inputStream.read()) != -1) {
byteStream.write(nextValue);
}
} catch (IOException e) {
e.printStackTrace();
}
buffer = byteStream.toByteArray();
return buffer;
}
}
请确保两个 classes 在不同的包中,否则稍后 JVM 会抱怨它们没有被签名。
我们在基础目录中,源代码在文件夹src
.
# Compile source files (JDK used for compilation is unimportant)
javac --release 8 src\org\acme\app\Main.java src\org\acme\loader\CustomClassLoader.java
# Create JAR containing custom class loader
jar cf CustomClassLoader.jar -C src org\acme\loader\CustomClassLoader.class
# Create signing key (default keystore has password 'changeit')
keytool -genkeypair -keyalg RSA -alias test-user
# Sign JAR (default keystore has password 'changeit')
jarsigner CustomClassLoader.jar test-user
# Run dummy application, setting custom class loader from JAR as system class loader
"c:\Program Files\Java\jdk-11.0.11\bin\java.exe" -Djava.security.debug="jca" -Djava.system.class.loader=org.acme.loader.CustomClassLoader -cp "CustomClassLoader.jar;src" org.acme.app.Main
改变 java.exe
的路径,以查看问题确实只发生在 JDK 11.0.11.
更新: 我刚刚向 Oracle 提交了一份 JDK 错误报告(内部审核 ID 9070863)。一旦收到他们的来信并且该错误在 public 错误数据库中,我将再次更新此答案。
更新 2: 错误报告 JDK-8270170 经过验证后现在可见。
我在 start/run Java Java 工具套件 4.11(基于 Eclipse 2021-06)中使用 Spring 工具套件中的 AspectJ Load-Time-Weaving 应用程序时遇到问题=] 11.0.11 运行时(使用 AdoptOpenJDK 11.0.11.9-hotspot 或 Oracle JDK build 11.0.11+9-LTS-194 或 Zulu11.48+21-CA(build 11.0.11 +9-LTS) 在 Windows 上 10) 当访问 javax.net.ssl.SSLContext
时。对于较旧的 Java 11 版本,不会出现此问题。
我已将问题简化为一个小应用程序:
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException {
String cp = System.getProperty("java.class.path");
System.err.println(cp);
String cn = System.getProperty("java.system.class.loader");
System.err.println(cn);
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
}
}
该应用程序在 Eclipse 中使用 AspectJ LTW 启动配置启动。 我得到的输出和异常是这样的:
D:\sts-4.11.0.RELEASE\plugins\org.aspectj.weaver_1.9.6.202103162301.jar;D:\sts-4.11.0.RELEASE\plugins\org.aspectj.runtime_1.9.6.202103162301.jar
org.aspectj.weaver.loadtime.WeavingURLClassLoader
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class sun.security.jca.ProviderConfig$ProviderLoader
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:248)
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:242)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:242)
at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:222)
at java.base/sun.security.jca.ProviderList.getProvider(ProviderList.java:266)
at java.base/sun.security.jca.ProviderList$ServiceList.tryGet(ProviderList.java:511)
at java.base/sun.security.jca.ProviderList$ServiceList.hasNext(ProviderList.java:565)
at java.base/java.security.Signature.getInstance(Signature.java:266)
at java.base/sun.security.ssl.JsseJce.getSignature(JsseJce.java:202)
at java.base/sun.security.ssl.JsseJce$EcAvailability.<clinit>(JsseJce.java:394)
at java.base/sun.security.ssl.JsseJce.isEcAvailable(JsseJce.java:175)
at java.base/sun.security.ssl.CipherSuite$KeyExchange.isAvailable(CipherSuite.java:1079)
at java.base/sun.security.ssl.CipherSuite.isAvailable(CipherSuite.java:941)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableCipherSuites(SSLContextImpl.java:384)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(SSLContextImpl.java:347)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:580)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1918)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.pmd.bug.Main.main(Main.java:18)
这是我使用 VM 参数 "-Djava.security.debug="jca"
:
ProviderList: provider configuration: [SUN, SunRsaSign, SunEC, SunJSSE, SunJCE, SunJGSS, SunSASL, XMLDSig, SunPCSC, JdkLDAP, JdkSASL, SunMSCAPI, SunPKCS11]
ProviderList: config configuration: null
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Disabling ThreadLocal providers
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Loading all providers
java.lang.Exception: Debug Info. Call trace:
at java.base/sun.security.jca.ProviderList.loadAll(ProviderList.java:311)
at java.base/sun.security.jca.ProviderList.removeInvalid(ProviderList.java:332)
at java.base/sun.security.jca.Providers.getFullProviderList(Providers.java:165)
at java.base/java.security.Security.getProviders(Security.java:457)
at java.base/sun.security.x509.AlgorithmId.computeOidTable(AlgorithmId.java:637)
at java.base/sun.security.x509.AlgorithmId.oidTable(AlgorithmId.java:627)
at java.base/sun.security.x509.AlgorithmId.algOID(AlgorithmId.java:609)
at java.base/sun.security.x509.AlgorithmId.get(AlgorithmId.java:441)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:380)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.pkcs.SignerInfo.getTimestamp(SignerInfo.java:545)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:318)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:283)
at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:259)
at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)
at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:230)
at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:759)
at java.base/java.util.jar.JarFile.ensureInitialization(JarFile.java:1038)
at java.base/java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
at java.base/jdk.internal.loader.URLClassPath$JarLoader.getManifest(URLClassPath.java:870)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:786)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1976)
at java.base/java.lang.System.initPhase3(System.java:2074)
ProviderConfig: Loading provider SunEC
ProviderConfig: Error loading provider SunEC
java.lang.ExceptionInInitializerError
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:248)
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:242)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:242)
at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:222)
at java.base/sun.security.jca.ProviderList.loadAll(ProviderList.java:315)
at java.base/sun.security.jca.ProviderList.removeInvalid(ProviderList.java:332)
at java.base/sun.security.jca.Providers.getFullProviderList(Providers.java:165)
at java.base/java.security.Security.getProviders(Security.java:457)
at java.base/sun.security.x509.AlgorithmId.computeOidTable(AlgorithmId.java:637)
at java.base/sun.security.x509.AlgorithmId.oidTable(AlgorithmId.java:627)
at java.base/sun.security.x509.AlgorithmId.algOID(AlgorithmId.java:609)
at java.base/sun.security.x509.AlgorithmId.get(AlgorithmId.java:441)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:380)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.pkcs.SignerInfo.getTimestamp(SignerInfo.java:545)
at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:318)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578)
at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595)
at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:283)
at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:259)
at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)
at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:230)
at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:759)
at java.base/java.util.jar.JarFile.ensureInitialization(JarFile.java:1038)
at java.base/java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
at java.base/jdk.internal.loader.URLClassPath$JarLoader.getManifest(URLClassPath.java:870)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:786)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1976)
at java.base/java.lang.System.initPhase3(System.java:2074)
Caused by: java.lang.IllegalStateException: getSystemClassLoader cannot be called during the system class loader instantiation
at java.base/java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1932)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<init>(ProviderConfig.java:323)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<clinit>(ProviderConfig.java:313)
... 38 more
ProviderList: Disabling ThreadLocal providers
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Disabling ThreadLocal providers
ProviderList: ThreadLocal providers: [SUN, SunRsaSign, SunEC, SunJCE]
ProviderList: Disabling ThreadLocal providers
D:\sts-4.11.0.RELEASE\plugins\org.aspectj.weaver_1.9.6.202103162301.jar;D:\sts-4.11.0.RELEASE\plugins\org.aspectj.runtime_1.9.6.202103162301.jar
org.aspectj.weaver.loadtime.WeavingURLClassLoader
Hello World!
ProviderConfig: Loading provider SunJGSS
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class sun.security.jca.ProviderConfig$ProviderLoader
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:248)
at java.base/sun.security.jca.ProviderConfig.run(ProviderConfig.java:242)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:242)
at java.base/sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:222)
at java.base/sun.security.jca.ProviderList.getProvider(ProviderList.java:266)
at java.base/sun.security.jca.ProviderList$ServiceList.tryGet(ProviderList.java:511)
at java.base/sun.security.jca.ProviderList$ServiceList.hasNext(ProviderList.java:565)
at java.base/java.security.Signature.getInstance(Signature.java:266)
at java.base/sun.security.ssl.JsseJce.getSignature(JsseJce.java:202)
at java.base/sun.security.ssl.JsseJce$EcAvailability.<clinit>(JsseJce.java:394)
at java.base/sun.security.ssl.JsseJce.isEcAvailable(JsseJce.java:175)
at java.base/sun.security.ssl.CipherSuite$KeyExchange.isAvailable(CipherSuite.java:1079)
at java.base/sun.security.ssl.CipherSuite.isAvailable(CipherSuite.java:941)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableCipherSuites(SSLContextImpl.java:384)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(SSLContextImpl.java:347)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:580)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1918)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.pmd.bug.Main.main(Main.java:18)
在我看来,当系统 class 加载程序在 Classloader#initSystemClassLoader
中初始化为 org.aspectj.weaver.loadtime.WeavingURLClassLoader
时,一些步骤之后会以某种方式触发所有安全提供程序的加载,而这又需要访问系统 class 加载程序(尚未完全初始化)。
这导致日志的这一部分:
Caused by: java.lang.IllegalStateException: getSystemClassLoader cannot be called during the system class loader instantiation
at java.base/java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1932)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<init>(ProviderConfig.java:323)
at java.base/sun.security.jca.ProviderConfig$ProviderLoader.<clinit>(ProviderConfig.java:313)
稍后在应用程序中调用 SSLContext.getInstance("TLS"),再次需要 sun.security.jca.ProviderConfig$ProviderLoader,但这次因 NoClassDefFoundError 而失败。
你觉得我的分析正确吗?
这是 OpenJDK 11.0.11 中的(潜在)错误吗?
这个问题有解决办法吗?
更新 (06.07.21):
I found out 如何查看 Eclipse 启动配置产生的完整命令行调用。这是:
C:\Programme\Java\jdk-11.0.11.9-hotspot\bin\javaw.exe -Djava.security.debug=jca -Djava.system.class.loader=org.aspectj.weaver.loadtime.WeavingURLClassLoader -Daj.class.path=D:\workspace\sts490\edrewemaster\example-demo\target\classes;D:\workspace\sts490\edrewemaster\example-demo\target\test-classes;D:\repo\org\aspectj\aspectjrt.9.6\aspectjrt-1.9.6.jar;D:\workspace\sts490\edrewemaster\example-demo\target\classes -Dfile.encoding=Cp1252 -classpath D:\sts-4.11.0.RELEASE\plugins\org.aspectj.weaver_1.9.6.202103162301.jar;D:\sts-4.11.0.RELEASE\plugins\org.aspectj.runtime_1.9.6.202103162301.jar org.pmd.bug.Main
当我像这样从命令行 运行 时(使用 java 而不是 javaw),我也得到了异常。当我使用像
这样的旧 Java 版本 (11.0.10) 时C:\Programme\Java.0.10_9_adopt\jdk-11.0.10+9\bin\java ...
有效。
所以 Eclipse 似乎取代了 LTW 的系统 class 加载程序。有没有办法告诉 Eclipse 将 LTW 与 java 代理解决方案一起使用?也许这可以解决这个问题?
我想我找到了解决方法:不要使用类型为“AspectJ Load-Time Weaving Application”的 Eclipse 启动配置,而是使用普通的 Java 应用程序启动配置并通过“-javaagent”标志启用 LTW,例如
-javaagent:D:\repo\org\aspectj\aspectjweaver.9.6\aspectjweaver-1.9.6.jar
这对我有用。
我做了几个实验,发现问题所在
- 与AspectJ完全无关,
- 一般来说与Java代理完全无关,
- 发生当且仅当
-
使用
-Djava.system.class.loader
和- 有问题的系统 class 加载程序在签名的 JAR 中找到并且
- 该应用程序在 JDK 11.0.11 上运行(不是 11.0.10 或我测试过的任何其他 JDK 9-16)。
一旦我从 META-INF
目录中删除 JAR 签名,它也适用于 JDK 11.0.11。 IMO,这是 JDK 中的回归错误,应该修复。这是一个最小的测试用例:
package org.acme.app;
public class Main {
public static void main(String[] args) {}
}
package org.acme.loader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class CustomClassLoader extends ClassLoader {
public CustomClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassFromFile(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassFromFile(String fileName) {
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream(fileName.replace('.', File.separatorChar) + ".class");
byte[] buffer;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
while ((nextValue = inputStream.read()) != -1) {
byteStream.write(nextValue);
}
} catch (IOException e) {
e.printStackTrace();
}
buffer = byteStream.toByteArray();
return buffer;
}
}
请确保两个 classes 在不同的包中,否则稍后 JVM 会抱怨它们没有被签名。
我们在基础目录中,源代码在文件夹src
.
# Compile source files (JDK used for compilation is unimportant)
javac --release 8 src\org\acme\app\Main.java src\org\acme\loader\CustomClassLoader.java
# Create JAR containing custom class loader
jar cf CustomClassLoader.jar -C src org\acme\loader\CustomClassLoader.class
# Create signing key (default keystore has password 'changeit')
keytool -genkeypair -keyalg RSA -alias test-user
# Sign JAR (default keystore has password 'changeit')
jarsigner CustomClassLoader.jar test-user
# Run dummy application, setting custom class loader from JAR as system class loader
"c:\Program Files\Java\jdk-11.0.11\bin\java.exe" -Djava.security.debug="jca" -Djava.system.class.loader=org.acme.loader.CustomClassLoader -cp "CustomClassLoader.jar;src" org.acme.app.Main
改变 java.exe
的路径,以查看问题确实只发生在 JDK 11.0.11.
更新: 我刚刚向 Oracle 提交了一份 JDK 错误报告(内部审核 ID 9070863)。一旦收到他们的来信并且该错误在 public 错误数据库中,我将再次更新此答案。
更新 2: 错误报告 JDK-8270170 经过验证后现在可见。