import org.apache.commons.codec.binary.Hex;import org.apache.commons.codec.digest.DigestUtils;import org.apache.commons.codec.digest.HmacUtils;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;public class Encryptor {public String encrype(String s) {MessageDigest sha256Digest = DigestUtils.getSha256Digest();String result = Hex.encodeHexString(sha256Digest.digest(s.getBytes(StandardCharsets.UTF_8)));return Hex.encodeHexString(HmacUtils.getHmacSha256(result.getBytes()).doFinal(result.getBytes()));}public static void main(String[] args) {Encryptor encryptor = new Encryptor();String s = "test";String result = encryptor.encrype(s);System.out.println(result);}/**output: fdd04dcac94e9803a72e4268141f773e2024a8fe46ba19a263be22c5ca83e931**/}
执行单元测试可以正常运行。但是当整个应用启动时,则会报 IllegalAccessError 错误。
public String encrype(String s) {try {MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");String result = Hex.encodeHexString(sha256Digest.digest(s.getBytes(StandardCharsets.UTF_8)));return Hex.encodeHexString(HmacUtils.getHmacSha256(result.getBytes()).doFinal(result.getBytes()));} catch (NoSuchAlgorithmException e) {e.printStackTrace();return "error";}}
<dependencies><dependency><groupId>com.chaycao.maven.dependency</groupId><artifactId>A</artifactId><version>1.0-SNAPSHOT</version><exclusions><exclusion><artifactId>commons-codec</artifactId><groupId>commons-codec</groupId></exclusion></exclusions></dependency><dependency><groupId>com.chaycao.maven.dependency</groupId><artifactId>Y</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
注意:代码的编译仅仅是编译当前的代码。编译成功后,最后能否正常运行,还要取决于运行时的环境是否等同或兼容编译时环境。
下面我们想想为什么需要 Maven 依赖调解,如果不调解行不行。
当使用 Maven 的过程中,如果同时引入了 groupId 和 artifactId 相同而 version 不同的包时,Maven 会认为发生了依赖冲突,将进行依赖调解,通过两个原则决定使用哪个版本的包:第一原则,路径最近者优先,如前文。如果路径相同,则使用第二原则,在 pom 中第一声明者优先。而当我们在点击 Run 运行时,classpath 中将只会有一个明确版本的包。
思考一下。Java 在运行时,是否能引入版本不同的包。其实这个问题是在问,java 命令的 classpath 参数中能不能有多个版本不同的包,当然是可以的。classpath 参数的是用于指示JVM如何搜索 class 文件,当你在 classpath 中指定的路径下有多个版本不同的包,JVM 都会去 jar 包下搜索 class 文件进行加载,而至于 class 能不能成功加载,则在于 ClassLoader 的逻辑,当同名类被加载时,则不会再被加载,即同一个类只会被加载一次。这也意味,当有多个版本不同的包时,包在 classpath 中的顺序,决定了哪个包中的类能先被加载。而这样具有不确定性。因为在生产环境下通常使用shell命令将 jar 包拼接:
LIB_DIR=libLIB_JARS=`ls $LIB_DIR|grep .jar|awk '{print "'$LIB_DIR'/"$0}'|tr "\n" ":"`
public class Main {public static void main(String[] args) {while (true) {try {Encryptor encryptor = new Encryptor();String s = "1234567890";String result = encryptor.encrype(s);System.out.println(result);} catch (Throwable e) {}}}}
[arthas@32328]$ sc -d org.apache.commons.codec.digest.DigestUtilsclass-info org.apache.commons.codec.digest.DigestUtilscode-source /D:/mavenrepo/commons-codec/commons-codec/1.6/commons-codec-1.6.jarname org.apache.commons.codec.digest.DigestUtilsisInterface falseisAnnotation falseisEnum falseisAnonymousClass falseisArray falseisLocalClass falseisMemberClass falseisPrimitive falseisSynthetic falsesimple-name DigestUtilsmodifier publicannotationinterfacessuper-class +-java.lang.Objectclass-loader +-sun.misc.Launcher$AppClassLoader@58644d46+-sun.misc.Launcher$ExtClassLoader@24e74ca5classLoaderHash 58644d46
可以从 code-source 中清晰的查到 DigestUtils 是哪个包下的 Class,这时就该意识到发生了依赖冲突问题。
而通过 jad 命令,还能反编译,在线看代码。好用!
![]()
更多精彩推荐
☞倪光南、求伯君“出山”:爱解 Bug、无惧“35岁魔咒”、编码之路痛并快乐!
☞腾讯回应发布虚假广告被罚20万;苹果客服回应iPhone 12屏幕发绿;Chrome 87 正式版发布|极客头条![]()
点分享 ![]()
点点赞 ![]()
点在看