java调用dll异常的处理(UnsatisfiedLinkError)

背景描述

因业务需要,java项目需要调用dll进行MD5加密处理。dll是其它项目组提供的,基于64位平台编译的;java项目是基于maven的。
我把dll文件放在resources目录下,相关代码如下:
加载dll方法的类:
public class NativeMethod{

public native String getC4MD5(String pwd);

public String getC4MD51(String pwd){
String filePath = this.getClass().getClassLoader().getResource("/").getPath();
filePath +="Md5.dll";
try {
filePath = java.net.URLDecoder.decode(filePath, "utf-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
filePath = filePath.startsWith("/") ? filePath.substring(1) : filePath;
        File file=new File(filePath.replaceAll("/", "\\\\"));
System.load(file.toString());
return getC4MD5(pwd);
}

}

调用方式:

public Map doLogin(String userName,String password){
Map resultMap = new HashMap();
try {
NativeMethod n =  new NativeMethod();
String pwd = n.getC4MD51(password);
System.out.println("pwd:" + pwd);
resultMap.put("pwd", pwd);
} catch (Exception e) {
e.printStackTrace();
resultMap.put("result", false);
resultMap.put("error", e);
}
return resultMap;
}


问题描述

接下来记录调用过程中碰到的两个主要问题:
1.JDK版本问题,由于dll是64位的,而我的JDK是32位的,所以会报平台兼容性的错误。解决方案就是把JDK替换成64位版本的。这方面的资料百度上一搜一大堆,这里就不作展开。
2.JDK版本替换成64位之后,通过myeclipse直接部署到tomcat上,可以正常运行,调用加密方法也正常。以为大功告成,于是通过maven打成war,部署到服务器上,结果报错:
2017-04-19 11:37:54  [ http-bio-8080-exec-10:10988 ] - [ DEBUG ]  Could not complete request
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.UnsatisfiedLinkError: D:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\bss\WEB-INF\classes\Md5.dll: Can't load this .dll (machine code=0xbd) on a AMD 64-bit platform
at org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletionWithError(DispatcherServlet.java:1302)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:977)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:859)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)

奇怪啊,本地跑的好好的,怎么到服务器上就不行了呢?百思不得其解。


解决方案

折腾了好久,最后在stackoverflow上找到了解决方法。
参考链接:http://stackoverflow.com/questions/38244970/running-my-generated-jar-yields-cant-load-this-dll-machine-code-0xbd-on-a

原文如下:

I experienced the same problem when I tried to run the JAR that was built by Maven (but with a 32 bit DLL - Can't load this .dll (machine code=0xbd) on a IA 32-bit platform). Strange thing was: It happened after I moved the DLL in a folder with other resources which have to be copied during the build.

I took me a quite a while to find out that the maven resources plugin was changing the DLL file for some reason (might be a bug?). The original DLL file is 76 kb - the copied DLL in the target folder was 118 kb. Something happened to the file during build.

Adding an extra execution to copy the DLL files without true solved the problem.

根据这位大神的描述,是maven在打包的时候对dll做了某种不可知的修改,导致修改后的dll无法使用。
我把war包里的dll文件取出来和原文件一比较,果然如此:原文件123k,war取出来的195k,确实是maven引起的问题。
再查看maven工程的pom.xml,打包相关配置如下:

src/main/resources
true

**/*.xml
**/*.properties
**/*.dll


然后根据这位大神说的,把filtering注释掉,改成如下:

src/main/resources


再次编译,问题解决。
或许,如这位大神所说,这真的是maven的一个bug吧。

你可能感兴趣的:(java调用dll异常的处理(UnsatisfiedLinkError))