我認爲它與此有關:Do security providers cause ClassLoader leaks in Java?。基本上Security
是重新使用舊的類加載器的提供者。所以這可能發生在任何多類路徑環境(如OSGi)中,而不僅僅是SBT。
修復您build.sbt
(無分叉):
testOptions in Test += Tests.Cleanup(() =>
java.security.Security.removeProvider("BC"))
實驗:
sbt-classloader-issue$ sbt
> test
[success] Total time: 1 s, completed Jul 6, 2017 11:43:53 PM
> test
[success] Total time: 0 s, completed Jul 6, 2017 11:43:55 PM
說明:
,我可以從你的代碼中看到(發表here):
Security.addProvider(new BouncyCastleProvider)
您每次運行測試時都重複使用相同的BouncyCastleProvider
提供程序,因爲您的Security.addProvider
工程only first time。由於sbt爲每次「測試」運行創建了新的類加載器,但重新使用相同的JVM - Security
是JVM-bootstrap加載的JVM範圍的單例,因此classOf[java.security.Security].getClassLoader() == null
和sbt無法重新加載/重新初始化此類。
而且你可以方便地查看
classOf[org.bouncycastle.jce.spec.ECParameterSpec].getClassLoader()
res30: ClassLoader = URLClassLoader with NativeCopyLoader with RawResources
org.bouncycastle
類加載自定義類加載(從SBT),它改變了你運行test
的每次。
所以這個代碼:
val generator = KeyPairGenerator.getInstance("ECDSA", "BC")
會從舊的類加載器(一個用於第一次「測試」運行)加載的類的實例,你想與新的類加載器的規格將其初始化:
generator.initialize(ecSpec)
這就是爲什麼你會得到「參數對象不是ECParameterSpec」異常。 「net.i2p.crypto.eddsa.EdDSAPublicKey不能轉換爲net.i2p.crypto.eddsa.EdDSAPublicKey」的推理基本相同。
你能否在你的問題中包含重現此問題的代碼?爲什麼你認爲類加載器是問題? –
我最終爲sbt寫了一個問題報告來嘗試和調試這個,請查看https://github.com/sbt/sbt/issues/3306我寫了一個小項目來重現這個問題 – simao