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.Base6四、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
沒有問題的話,仍是採用這種方式吧
附件列表