Bouncy Castle 多版本 与 Classloader 的问题
2011-03-26 11:51
639 查看
最近在做一个安全工具, 需要与多个第三方公司进行安全通信, 其中就用到了Bouncy Castle.
在连接B公司时,偶尔就会出现这样的异常:
代码大概是这样的
provider=new org.bouncycastle.jce.provider.BouncyCastleProvider()
Security.addProvider(provider);
CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");
// Read the Private Key
KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
ks.load(new FileInputStream(keyPath), keyPass.toCharArray()); //执行到这里报错
为什么呢? 分析过程
1. 打开WEB-INF/lib/bcprov-jdk15-133.jar, 所有类以及依赖都有. 那怎么会报异常呢?
2. 打开调试器, 查看"Security.getProvider("BC").getClass().getClassLoader()", 发现这个classloader根本就是web应用的classloader,而是一个自定义的classloader, 找到它加载的jar, 打开一看, 果然找不到RC2Engine, 因为它加载的是一个低版本的bcprov-jdk13.jar
原来如此
当A classloader加载BouncyCastleProvider 1.3版已经注册后"Security.addProvider(provider)",B公司的安全组件通过 Webapp classloader 加载的BouncyCastleProvider 1.5版 自然就注册不进去了, 所以初始化失败,报了本文开始提的异常.
解决办法
将A 公司使用的BouncyCastleProvider 1.3升级为1.5, 问题就解决了.
问题总结
我们都知道, java的classloader相当于一个命名空间, 当要加载一个类时, 会通过双亲委派机制,先让父加载器加载,加载不成功才由自己加载, 而与兄弟加载器是隔离的.
所以当发现此类问题时, 可以通过"obj.getClass().getClassLoader()"先看看到底由哪个加载器加载的. 在依次找,是哪个类加载器出了问题.
在连接B公司时,偶尔就会出现这样的异常:
java.lang.NoClassDefFoundError: org/bouncycastle/crypto/engines/RC2Engine at org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd40BitRC2.<init>(JCEBlockCipher.java:906) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at java.lang.Class.newInstance0(Class.java:355) at java.lang.Class.newInstance(Class.java:308) at java.security.Provider$Service.newInstance(Provider.java:1221) at javax.crypto.Cipher.getInstance(DashoA13*..) at javax.crypto.Cipher.getInstance(DashoA13*..) at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.decryptData(JDKPKCS12KeyStore.java:590) at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(JDKPKCS12KeyStore.java:802) at java.security.KeyStore.load(KeyStore.java:1185)
代码大概是这样的
provider=new org.bouncycastle.jce.provider.BouncyCastleProvider()
Security.addProvider(provider);
CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");
// Read the Private Key
KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
ks.load(new FileInputStream(keyPath), keyPass.toCharArray()); //执行到这里报错
为什么呢? 分析过程
1. 打开WEB-INF/lib/bcprov-jdk15-133.jar, 所有类以及依赖都有. 那怎么会报异常呢?
2. 打开调试器, 查看"Security.getProvider("BC").getClass().getClassLoader()", 发现这个classloader根本就是web应用的classloader,而是一个自定义的classloader, 找到它加载的jar, 打开一看, 果然找不到RC2Engine, 因为它加载的是一个低版本的bcprov-jdk13.jar
原来如此
当A classloader加载BouncyCastleProvider 1.3版已经注册后"Security.addProvider(provider)",B公司的安全组件通过 Webapp classloader 加载的BouncyCastleProvider 1.5版 自然就注册不进去了, 所以初始化失败,报了本文开始提的异常.
解决办法
将A 公司使用的BouncyCastleProvider 1.3升级为1.5, 问题就解决了.
问题总结
我们都知道, java的classloader相当于一个命名空间, 当要加载一个类时, 会通过双亲委派机制,先让父加载器加载,加载不成功才由自己加载, 而与兄弟加载器是隔离的.
所以当发现此类问题时, 可以通过"obj.getClass().getClassLoader()"先看看到底由哪个加载器加载的. 在依次找,是哪个类加载器出了问题.
相关文章推荐
- tq2440编译ARM版本的Qt4出错问题解决
- win7下的PHP+IIS配置,找不到php5isapi.dll的问题,版本5.4.9
- Python2.7以上版本解决 "ImportError: No module named MySQLdb"问题
- mysqldump版本引起的问题
- Java序列化机制中的类版本问题 serialVersionUID的静态字段 含义
- SVN使用:用TortoiseSVN查看Log 无法显示最新的版本和Log信息问题
- scrapy在python3版本运行问题
- svn冲突问题详解 SVN版本冲突解决详解
- cvs 版本分支问题
- 问个开发的版本小问题~
- 关于Myeclipse中jdk版本问题
- Spring学习总结(22)——Spring-framework-bom解决spring的不同模块依赖版本不同问题
- android调用高版本api函数的兼容性问题
- keil5因为J-Link版本过高闪退问题
- 解决 “IntelliJ IDEA 使用SVN版本控制频繁弹出输入 用户名和密码的弹框” 问题
- DDK 编译版本问题
- 启动hive 遇到jline 版本冲突问题解决
- 【Android】两步搞定AndroidSDKManager在线更新SDK版本失败问题
- php calender(日历)二个版本代码示例(解决2038问题)