Spring
提供的
org.springframework.util.Base64Utils
类,先会检测JDK里是否自带java.util.Base64,如果不带,则
使用的是
apache
提供的org.apache.commons.codec.binary.Base64:
经过一段时间的生产试运行来看,
在多线程环境中Base64Utils会出各种异常,比如这样的异常:
java.lang.ArrayIndexOutOfBoundsException: null
at org.apache.commons.codec.binary.BaseNCodec.readResults(BaseNCodec.java:209)
at org.apache.commons.codec.binary.BaseNCodec.decode(BaseNCodec.java:324)
at org.springframework.util.Base64Utils$CommonsCodecBase64Delegate.decode(Base64Utils.java:164)
at org.springframework.util.Base64Utils.decodeFromString(Base64Utils.java:124)
...
java.lang.NullPointerException: null
at java.lang.System.arraycopy(Native Method)
at org.apache.commons.codec.binary.BaseNCodec.readResults(BaseNCodec.java:209)
at org.apache.commons.codec.binary.BaseNCodec.decode(BaseNCodec.java:324)
at org.springframework.util.Base64Utils$CommonsCodecBase64Delegate.decode(Base64Utils.java:164)
at org.springframework.util.Base64Utils.decodeFromString(Base64Utils.java:124)
...
又或者没抛异常,但Base64Utils.decodeFromString解出的数据已经不准确了,比如此时用它解码出的数据或秘钥来进行解密的话,会出类似如下异常:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.DESedeCipher.engineDoFinal(DESedeCipher.java:294)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
...
但具体由哪个类引起的并发,原因有待分析,可能与JDK版本、org.apache.commons.codec.binary.Base64、java.util.Base64都有关系
,不管问题出在哪,在使用Base64Utils的地方,加上同步应该即可解决:
synchronized (Base64Utils.class) {
key = Base64Utils.decodeFromString(keyBase64);
}
synchronized (Base64Utils.class) {
rtnValue = Base64Utils.encodeToString(data);
}
或者不使用
org.springframework.util.Base64Utils,而是直接使用
apache
提供的org.apache.commons.codec.binary.Base64(相应方法:Base64.decodeBase64(keyBase64),Base64.encodeBase64String(data))
,并发环境下目前发现没有问题,代码参见附件!!
由于
synchronized
同步会引起性能问题,如果直接使用org.apache.commons.codec.binary.Base64
没有问题的话,还是采用这种方式吧
附件列表