1、背景

最近接手的项目,底层算法是C++写的,并且封装成了dll。而目前的需求,需要把这些算法移到服务端执行。不可能把C++写的算法库改用Java重写一遍,而且也基于执行效率的考虑,采用Java调用dll的方案

2、依赖包

添加依赖如下:

<dependency>
	<groupId>net.java.dev.jna</groupId>
	<artifactId>jna</artifactId>
	<version>5.7.0</version>
</dependency>

3、常见的写法

查资料,经常见到如下的实现

import com.sun.jna.Library;
import com.sun.jna.Native;

public class XXXX {
    ...
    public interface JnaDll extends Library {
        int funname(String content);
        JnaDll jnaDll = (JnaDll)Native.load("D:\\xx\\...\\xx", JnaDll.class);
    }
    ...
    public void xxxx() {
        int result = JnaDll.jnaDll.funname("xxx");
        ...
    }
}

4、局限性

可以看到,dll路径是写死在代码里的。

如果需要将dll路径放到配置文件中怎么办?即需要放到application-xxx.yml中。

5、解决方案

我们可以把dll的方法封装成Java服务,如下:

import com.sun.jna.Library;
import com.sun.jna.Native;

@Service
public class XXXX {
    @Value("${xx.xx}")
    private String dllPath;
    ...
    private interface JnaDll extends Library {
        int funname(String content);
        int funname2(Pointer pointer);
    }
    JnaDll jnaDll;
    private JnaDll getJnaDll() {
        if (jnaDll == null) {
            jnaDll = (JnaDll)Native.load(this.dllPath, JnaDll.class);
        }
        return jnaDll;
    }
    ...
    public void xxxx() {
        int result = getJnaDll().funname("xxx");
        ...
    }
}

6、分析

(1)代码中的接口JnaDll其实只是个申明,是dll中C方法的封装,这个接口只在当前类中有效即可,所以可以申明为私有接口

(2)相应的变量在哪里都可以申明和实例化,不一定只能属于该接口,也不一定只能申明时实例化

7、参数说明

(1)从dll中返回字符串,接口定义返回类型为const char*,没成功,只好将传入参数类型改为char*,而Java中对接的参数为Pointer。

调用方法传参前,要保存空间足够,写法如下:

Pointer pointer = new Memory(xxxx);
getJnaDll().funname2(pointer);

(2)只是给dll传入const char*,不需要dll返回字符串,则传入String即可。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐