SpringBoot项目,运行在linux环境中,如何引用 .so 动态链接库文件

SpringBoot项目,运行在linux环境中,如何引用 .so 动态链接库文件

不同于在windows环境下调用dll文件,在linux下调用dll的话,会报错:Caused by: java.lang.UnsatisfiedLinkError: /root/hgs/Odbc.dll: /root/hgs/Odbc.dll: 无效的 ELF 头 (Possible cause: endianness mismatch),这是因为dll是在windows下的动态库,在linux应该调用so动态库

Caused by: java.lang.UnsatisfiedLinkError: /root/hgs/Odbc.dll: /root/hgs/Odbc.dll: 无效的 ELF 头 (Possible cause: endianness mismatch)
	at java.lang.ClassLoader$NativeLibrary.load(Native Method) ~[na:1.8.0_333]
	at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1937) ~[na:1.8.0_333]
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1820) ~[na:1.8.0_333]
	at java.lang.Runtime.load0(Runtime.java:810) ~[na:1.8.0_333]
	at java.lang.System.load(System.java:1086) ~[na:1.8.0_333]
	at com.example.demo.util.CommonUtil.<clinit>(CommonUtil.java:41) ~[classes!/:1.0.3.RELEASE]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_333]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_333]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_333]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_333]
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:204) ~[spring-beans-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312) ~[spring-beans-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
	... 39 common frames omitted

dll与lib是Windows下描述封装代码库的一种格式,.a,.so是linux下的。dll与.so是动态库,lib与.a是静态库。

一、在linux下创建C++文件,并生成so动态库

在linux服务器上,任意一路径下,创建 jna.hjna.c文件

jna.h
int add(int a, int b);
int minus(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);
jna.c
#include "jna.h" 
int add(int a, int b)
{
	return a + b;
}

int minus(int a, int b)
{
	return a - b;
}

int multiply(int a, int b)
{
	return a * b;
}

double divide(int a, int b)
{
	double m = (double)a / b;
	return m;
}

在同路径下执行命令,生成so文件:

gcc -shared -fPIC jna.c -o libjna.so

目录结构如下

[root@196 jna]# tree
.
├── jna.c
├── jna.h
└── libjna.so

二、SpringBoot项目

代码结构
├─src
│  └─main
│      ├─java
│      │  └─com
│      │      └─example
│      │          └─demo
│      │              │  DemoApplication.java
│      │              │
│      │              ├─controller
│      │              │      JnaController.java
│      │              │
│      │              ├─entity
│      │              │      TestEntity.java
│      │              │
│      │              ├─service
│      │              └─util
│      │                      CommonUtil.java
│      │                      JnaInterface.java
│      │                      Test.java
│      │
│      └─resources
│          │  application.yml 
│          │
│          └─static
│                  libjna.so   --- linux下的动态链接库

JnaController.java
package com.example.demo.controller;

import com.example.demo.entity.TestEntity;
import com.example.demo.util.CommonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RequestMapping("test")
public class JnaController {
    @Autowired
    private CommonUtil commonUtil;

    @PostMapping("/")
    public int addTest(@RequestBody TestEntity testEntity)
    {
        return commonUtil.test(testEntity);

    }
}
TestEntity.java
package com.example.demo.entity;

import lombok.Data;
 
@Data
public class TestEntity {
    private String type;
    private int num1;
    private int num2;

}
CommonUtil.java
package com.example.demo.util;

import com.example.demo.entity.TestEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
 
@Component
@Slf4j
public class CommonUtil {
    static {
        try {
            log.info("start-------------------------");
            //将项目中的so文件,读取成inputStream
            InputStream is = new ClassPathResource("/static/libjna.so").getInputStream();
            String libPaths = System.getProperty("java.library.path");
            //":/root/hgs/sources:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib";
            if (StringUtils.isNotEmpty(libPaths) && libPaths.split(":").length > 1) {
              
                //linux系统中设置的动态库路径
                String sourcePath = libPaths.split(":")[1];   // /root/hgs/sources
                
                //将项目中的so文件,保存到其中一个动态库路径下
                File file = new File(sourcePath + "/libjna.so");
                inputStreamToFile(is, file);
                
                //因为linux下,访问动态链接库,会自动忽略文件名前面的lib,只需要写lib后面的内容(jna)即可访问到
                System.loadLibrary("jna");
            }
        } catch (Exception e) {
            log.error("----error,{}", e.getStackTrace()); 
        }
    }

    private static void inputStreamToFile(InputStream ins, File file)
    {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            log.error("--- inputstreamtofile error, {}", e.getMessage());
        }
    }

    public int test(TestEntity testEntity)
    {
        int num1 = testEntity.getNum1();
        int num2 = testEntity.getNum2();
        switch (testEntity.getType()) {
            case "add":
                return JnaInterface.INSTANCE.add(num1, num2);
            case "minus":
                return JnaInterface.INSTANCE.minus(num1, num2);
            case "multiply":
                return JnaInterface.INSTANCE.multiply(num1, num2);
            case "divide":
                double divide = JnaInterface.INSTANCE.divide(num1, num2);
                return (int) divide;
            default:
                return -1;
        }
    }
}
JnaInterface.java
package com.example.demo.util;
import com.sun.jna.Library;
import com.sun.jna.Native;
 
public interface JnaInterface extends Library {
    //这里跟CommonUtil.java里   System.loadLibrary("jna"); 写一样的名称(jna)
    JnaInterface INSTANCE = (JnaInterface) Native.loadLibrary("jna", JnaInterface.class);

    int add(int a, int b);

    int minus(int a, int b);

    int multiply(int a, int b);

    double divide(int a, int b);
}
DemoApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableScheduling
@EnableDiscoveryClient
@EnableTransactionManagement
@EnableFeignClients
public class DemoApplication {

    public static void main(String[] args)
    {
        SpringApplication.run(DemoApplication.class, args);
    }
}
application.yml
spring:
  application:
    name: jna-service
server:
  port: 16006
  http:
    encoding:
      charset: UTF-8
      enabled: true
      force: true
    port: 16010

maven编译程序,生成jna-service.jar,上传到linux环境中去,然后执行

java -jar jna-service.jar

请添加图片描述

运行成功!

使用postman调用:

http://xx.xx.xx.xx:16006/test/

POST

入参体:
{
    "type": "add",
    "num1": 143,
    "num2": 151
}

调用成功!

port: 16010






 maven编译程序,生成jna-service.jar,上传到linux环境中去,然后执行

~~~shell
java -jar jna-service.jar

[外链图片转存中…(img-V8UNExgd-1680600671513)]

运行成功!

使用postman调用:

http://xx.xx.xx.xx:16006/test/

POST

入参体:
{
    "type": "add",
    "num1": 143,
    "num2": 151
}

调用成功!
请添加图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高考我军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值