Java调C++避免JVM崩溃

前言

一般情况下很少用到Java调C++的场景,我们这次的场景是有个旧的打印服务是C++实现,旧服务重构较麻烦,就直接使用Java方式调用了

实现

dll方式

  1. 在idea中加一个external工具
    在这里插入图片描述

  2. Java代码生成接口方法,即native方法
    在这里插入图片描述

  3. 使用第一步中的添加的工具生成C++ .h文件

  4. 加载C++的dll文件
    Jni的这种调用容易引起jvm崩溃,大多数原因网络上说的内存溢出,有C++代码没有及时释放内存导致的内存泄漏也有创建线程过多等原因

@Slf4j
@Configuration
public class PrintOrderDllLoad {

    @Autowired
    private LegacyHHTServerService legacyHHTServerService;

    @Bean
    public PrintOrderDllHandler initDllHandler() {
        if (!SystemUtils.IS_OS_WINDOWS) {
            LoggerUtil.warn(log, "不是windows机器, 不load dll");
            return createDllHandler();
        }

        LoggerUtil.info(log,"开始加载dll文件");
        //注:使用System.load()时,文件名必须包含.dll后缀
        String path = legacyHHTServerService.getBasePath() + "/" + "HHTPrinterLibrary.dll";
        File file = new File(path);
        if(!file.exists()){
            LoggerUtil.error(log,"dll文件路径:{}不存在",path);
            throw new CommonBizException(CommonErrorCode.LOAD_DLL_FAILED, "dll文件加载失败,路径不存在");
        }

        try {
            System.load(path);
        } catch (Exception e) {
            LoggerUtil.error(log,"dll文件加载失败");
            throw new CommonBizException(CommonErrorCode.LOAD_DLL_FAILED, "dll文件加载失败");
        }
        LoggerUtil.info(log,"加载dll文件成功");

        /**
         * 初始化dllHandler类
         */
        return createDllHandler();
    }


    private PrintOrderDllHandler createDllHandler() {
        PrintOrderDllHandler printOrderDllHandler = new PrintOrderDllHandler();
        NativeMethod nativeMethod = new NativeMethod();
        printOrderDllHandler.setNativeMethod(nativeMethod);
        return printOrderDllHandler;
    }

}

cmd命令行方式

这种方式不存在jvm崩溃的问题,他只是新启动一个进程,代码中可以看出是启动了一个 .exe程序并给它传参数而已,不会影响jvm的进程

@Slf4j
@Service
public class CmdPrintInvoker {

    @Autowired
    private LegacyHHTServerService legacyHHTServerService;

    /**
     * cmd启动进程方式的打印
     */
    public void printOrderWithCmd(CmdPrintInputParamDTO cmdPrintInputParamDTO){
        LoggerUtil.info(log,"cmd命令开启打印进程,打印单据:{}",cmdPrintInputParamDTO.getPrintTypeParam().getOrderId());
        invokeCmd(cmdPrintInputParamDTO);
        LoggerUtil.info(log,"cmd命令结束打印进程,打印单据:{}",cmdPrintInputParamDTO.getPrintTypeParam().getOrderId());
    }

    private void invokeCmd(CmdPrintInputParamDTO cmdPrintInputParamDTO) {
        if (ObjectUtils.isEmpty(cmdPrintInputParamDTO)) {
            throw new CommonBizException(CommonErrorCode.NULL_PARAMETER, "调用cmd启动进程,参数不能为空");
        }
        List<String> cmdParamList = new ArrayList<>();
        String cmdParamJson = JSONObject.toJSONString(cmdPrintInputParamDTO);
        cmdParamJson = cmdParamJson.replaceAll("\"","\\\\\"");
        String printProcessExePath = legacyHHTServerService.getBasePath() + "/HHTPrinterLibraryConsoleWrapper.exe";
        cmdParamList.add(printProcessExePath);
        cmdParamList.add(cmdParamJson);
        CmdPrintExecuter cmdPrintExecuter = new CmdPrintExecuter();
        int result = cmdPrintExecuter.execute(cmdParamList);
        if(CmdPrintResultEnum.NORMAL_EXIT.getType() != result){
            CmdPrintResultEnum cmdPrintResultEnum = CmdPrintResultEnum.getByType(result);
            String exitDesc = null;
            if(!ObjectUtils.isEmpty(cmdPrintResultEnum)){
                exitDesc = cmdPrintResultEnum.getDesc();
            }
            LoggerUtil.info(log,"调用打印进程执行打印,进程退出异常:{}",exitDesc);
            throw new CommonBizException(CommonErrorCode.CMD_EXCUTE_ERROR,exitDesc);
        }

    }


}

@Slf4j
public class CmdPrintExecuter {

    public int execute(List<String> cmdStrList) {
        if (!SystemUtils.IS_OS_WINDOWS) {
            LoggerUtil.warn(log, "不是windows机器, 不调用打印cmd");
            return 0;
        }
        if(CollectionUtils.isEmpty(cmdStrList)){
            LoggerUtil.error(log,"命令行启动并执行进程,命令行参数不能为空");
            throw new CommonBizException(CommonErrorCode.ILLEGAL_PARAMETERS,"命令行启动并执行进程,命令行参数不能为空");
        }
        try {
            LoggerUtil.info(log,"命令行启动并执行进程开始,命令行参数:{}",cmdStrList);
            ProcessBuilder processBuilder = new ProcessBuilder(cmdStrList);
            processBuilder.redirectErrorStream(true);
            Process process = processBuilder.start();
            StringBuilder sb = new StringBuilder();
            new BufferedReader(new InputStreamReader(process.getInputStream())).lines()
                    .forEach(logStr -> {
                        sb.append(logStr);
                        sb.append("; ");
                    });
            LoggerUtil.info(log,"命令行启动进程输出日志:{}", sb.toString());
            int exitCode = process.waitFor();
            LoggerUtil.info(log,"命令行启动并执行进程结束,进程退出码exitCode:{}",exitCode);
            return exitCode;
        } catch (Exception e) {
            LoggerUtil.error(log, e,"命令行启动进程异常,命令行参数:{}",cmdStrList);
            throw new CommonBizException(CommonErrorCode.CMD_EXCUTE_ERROR,"命令行执行进程异常");
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值