zoukankan      html  css  js  c++  java
  • java调用JNI笔记

    一、环境

    CentOS7+jdk1.8
    开发:idea2021

    二、java调用指令

    pom.xml
    java调用JNI需要依赖外部的jar包,pom.xml引用如下,我使用的4.3.0版本。

    <!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>4.3.0</version>
    </dependency>
    

    JNI定义

    package com.fly.api;
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    /**
     * 其他的业务接口就不再此展示,仅保留两个示例接口
     * @author fly
     */
    public interface TLibrary extends Library {
        public TLibrary instance = (TLibrary) Native.loadLibrary("SID",TLibrary.class);
        /**
         * 开启线程
         * @return
         */
        int TStart(int threadNum);
    }
    

    业务调用

    private void action(){
        //接口调用
        Integer val= com.fly.api.TLibrary.instance.TStart(4);
        log.info("TStart.returnVal="+val);
    }
    

    三、Native.loadLibrary部分源码

    入口库就是我们java直接调用的c++库。经常会遇到在在各种目录下的各种问题。我们先看下Native.loadLibrary的核心实现逻辑。
    Native.loadLibrary入口类源码:

    public static <T> T loadLibrary(String name, Class<T> interfaceClass) {
        return loadLibrary(name, interfaceClass, Collections.<String, Object>emptyMap());
    }
    

    name说白了就是类库文件名(win系统.dll文件,linux系统为.so文件)
    注意:name需要去前缀lib。不论是win系统还是linux都一样的。如文件全名为:libTlibrary.dll(libTlibrary.so)则name="Tlibrary",lib前缀为底层约定。win下可以不带lib,源码就不在此展开了分析了。
    Native.loadLibrary核心逻辑说白了就是通过name找类库文件,找到文件后,通过解析与java接口中的方法一一对应。
    注:关于入口库文件的位置可以通过配置jna.library.path来修改所在目录。jna.library.path是通过System.getProperty("jna.library.path", "")。结合应用及系统自行配置就可以。我在应用中并没有配置此属性,不配置相关属性会通过类加载器去尝试加载类库。所以我将类库放在了应用的资源文件中。
    在loadLibrary中关键代码:

    File embedded = Native.extractFromResourcePath(libraryName, (ClassLoader)options.get(Library.OPTION_CLASSLOADER));
    

    对应extractFromResourcePath方法如下:

    public static File extractFromResourcePath(String name, ClassLoader loader) throws IOException {
        final boolean DEBUG = DEBUG_LOAD
            || (DEBUG_JNA_LOAD && name.indexOf("jnidispatch") != -1);
        if (loader == null) {
            loader = Thread.currentThread().getContextClassLoader();
            // Context class loader is not guaranteed to be set
            if (loader == null) {
                loader = Native.class.getClassLoader();
            }
        }
        if (DEBUG) {
            System.out.println("Looking in classpath from " + loader + " for " + name);
        }
        String libname = name.startsWith("/") ? name : NativeLibrary.mapSharedLibraryName(name);
        String resourcePath = name.startsWith("/") ? name : Platform.RESOURCE_PREFIX + "/" + libname;
        if (resourcePath.startsWith("/")) {
            resourcePath = resourcePath.substring(1);
        }
        URL url = loader.getResource(resourcePath);
        if (url == null && resourcePath.startsWith(Platform.RESOURCE_PREFIX)) {
            // If not found with the standard resource prefix, try without it
            url = loader.getResource(libname);
        }
        if (url == null) {
            String path = System.getProperty("java.class.path");
            if (loader instanceof URLClassLoader) {
                path = Arrays.asList(((URLClassLoader)loader).getURLs()).toString();
            }
            throw new IOException("Native library (" + resourcePath + ") not found in resource path (" + path + ")");
        }
        if (DEBUG) {
            System.out.println("Found library resource at " + url);
        }
            File lib = null;
            if (url.getProtocol().toLowerCase().equals("file")) {
                try {
                    lib = new File(new URI(url.toString()));
                }
                catch(URISyntaxException e) {
                    lib = new File(url.getPath());
                }
                if (DEBUG) {
                    System.out.println("Looking in " + lib.getAbsolutePath());
                }
                if (!lib.exists()) {
                    throw new IOException("File URL " + url + " could not be properly decoded");
                }
            }
            else if (!Boolean.getBoolean("jna.nounpack")) {
                InputStream is = loader.getResourceAsStream(resourcePath);
                if (is == null) {
                    throw new IOException("Can't obtain InputStream for " + resourcePath);
                }
                FileOutputStream fos = null;
                try {
                    // Suffix is required on windows, or library fails to load
                    // Let Java pick the suffix, except on windows, to avoid
                    // problems with Web Start.
                    File dir = getTempDir();
                    lib = File.createTempFile(JNA_TMPLIB_PREFIX, Platform.isWindows()?".dll":null, dir);
                    if (!Boolean.getBoolean("jnidispatch.preserve")) {
                        lib.deleteOnExit();
                    }
                    fos = new FileOutputStream(lib);
                    int count;
                    byte[] buf = new byte[1024];
                    while ((count = is.read(buf, 0, buf.length)) > 0) {
                        fos.write(buf, 0, count);
                    }
                }
                catch(IOException e) {
                    throw new IOException("Failed to create temporary file for " + name + " library: " + e.getMessage());
                }
                finally {
                    try { is.close(); } catch(IOException e) { }
                    if (fos != null) {
                        try { fos.close(); } catch(IOException e) { }
                    }
                }
            }
            return lib;
        }
    

    四、资源文件

    入口类库

    jni入口类库放在应用程序的资源目录下,具体的还要和开发、部署的系统有关系。
    如我部署的centos 64位,就需要在根资源目录上创建一个linux-x86-64的文件夹,将.so文件放在linux-x86-64文件夹中。

    依赖类库

    如果入口类库有依赖的类库,则需要将依赖的类库放在jre的相关目录中,并赋予可执行权限。
    jre安装目录:/usr/local/java/jdk1.8.0_121/jre
    则需要将依赖的类库放在目录:/usr/local/java/jdk1.8.0_121/jre/lib/amd64

  • 相关阅读:
    IE浏览器请求数据是提示下载的问题
    jS清除浏览器缓存
    JS获取时间戳
    keycode
    JS简单解决并发量
    写移动端流氓方法,无意看到,分享下
    CSS中的rem的换算
    jsp会话监听
    jsonp在jsp中的使用
    Java中的位运算符
  • 原文地址:https://www.cnblogs.com/pengei/p/14680778.html
Copyright © 2011-2022 走看看