Windows 10下Java keystore.load(null,null)加载过慢求助
Windows加载Windows-MY类型密钥库速度极慢的解决办法
在Windows 10系统(Java 1.8环境)中加载Windows-MY类型密钥库耗时约10秒,速度极慢。个人证书存储中仅有两张证书,尝试过修改SecureRandom属性的方案,但未解决问题。
原加载代码如下:
SunMSCAPI providerMSCAPI = new SunMSCAPI(); KeyStore ks = null; try { ks = KeyStore.getInstance("Windows-MY", providerMSCAPI); ks.load(null, null); Enumeration<String> aliases = ks.aliases(); while (aliases.hasMoreElements()){ String aliasName = (String) aliases.nextElement(); Certificate cert = ks.getCertificate(aliasName); if(cert instanceof X509Certificate){ X509Certificate x509Certificate = (X509Certificate)cert; String certSn = x509Certificate.getSerialNumber().toString(16); Date effectiveDate = x509Certificate.getNotBefore(); Date expireDate = x509Certificate.getNotAfter(); String subjectName = null; String issueName = null; String uid = null; LdapName ldapSubject = new LdapName(x509Certificate.getSubjectDN().getName()); LdapName ldapIssuer = new LdapName(x509Certificate.getIssuerDN().getName()); for(Rdn rdn : ldapSubject.getRdns()) { if(rdn.getType().equalsIgnoreCase("CN")) { subjectName = rdn.getValue().toString(); } if(rdn.getType().equalsIgnoreCase("UID")) { uid = rdn.getValue().toString(); } if(uid != null && subjectName != null){ break; } } for(Rdn rdn : ldapIssuer.getRdns()) { if(rdn.getType().equalsIgnoreCase("CN")) { issueName = rdn.getValue().toString(); break; } } if(uid != null){ certList.add(new CertificateData(certSn, subjectName, issueName, effectiveDate, expireDate, uid)); } }//end if }//end while } catch (KeyStoreException e) { response.setErrors(e.getLocalizedMessage()); } catch (CertificateException e) { response.setErrors(e.getLocalizedMessage()); } catch (IOException e) { response.setErrors(e.getLocalizedMessage()); } catch (NoSuchAlgorithmException e) { response.setErrors(e.getLocalizedMessage()); } catch (InvalidNameException e) { response.setErrors(e.getLocalizedMessage()); }
可行的解决建议
- 优化证书枚举逻辑
原代码会枚举密钥库中所有条目,包括非证书类型的条目(如密钥条目),可以先过滤出仅证书条目,减少无效处理:while (aliases.hasMoreElements()){ String aliasName = aliases.nextElement(); // 仅处理证书条目 if (!ks.isCertificateEntry(aliasName)) { continue; } Certificate cert = ks.getCertificate(aliasName); // 后续原有逻辑 } - 升级Java版本
Java 8的SunMSCAPI Provider存在已知的Windows证书存储访问性能问题,升级到Java 11及以上版本,官方对该模块的逻辑有优化,能大幅提升加载速度。 - 清理系统证书存储
即使可视化界面显示只有两张证书,系统可能存在隐藏的过期/无效证书条目。通过certmgr.msc打开证书管理器,清理个人存储中的无效证书,减少枚举时的系统开销。 - 跳过证书链验证
加载密钥库时,SunMSCAPI默认会验证证书链,可能触发额外的系统调用或网络请求。可以通过自定义LoadStoreParameter尝试跳过该验证:ks.load(null, null, new KeyStore.LoadStoreParameter() { @Override public KeyStore.ProtectionParameter getProtectionParameter() { return null; } }); - 更换证书访问方式
放弃使用SunMSCAPI,改用Windows的PowerShell命令预先导出证书到本地文件,再通过Java加载本地密钥库,避免直接访问系统证书存储的延迟。
内容的提问来源于stack exchange,提问作者kieuanhvu
相关产品推荐
相关产品推荐

