zoukankan      html  css  js  c++  java
  • java.library.path属性在代码中设置不生效问题 规格严格

    前两天想的屏幕抓图的程序,想给加个系统全局的热键,也就是说,在程序不处于当前激活下也可响应键盘事件。通过java自己应该是实现不了了。
    想到使用JNI,还好找到一篇介绍使用JIntellitype的文章,写得挺好的,下面的是链接:
    http://walsece.javaeye.com/blog/191169

    可是在使用上面文章介绍的动态库时,遇上了加载问题,也就是将动态库放到什么位置合适?文章中说可以放到System32目录,但我不想这样做,我更希望的是可以自己定制dll库的位置~~

    没有将lib放到System32目录,而是放到了自己的lib目录,程序在启动的过程中会报下面的错误:
    java.lang.UnsatisfiedLinkError: no JIntellitype in java.library.path

    根据上面的提示信息在VM参数处通过-Djava.library.path将加载路径指定到自己的lib目录后,程序可以正常启动。

    这种方式不是太好,因为要手动的去指定虚拟机参数,于是想通过System类的setProperty函数来在代码中动态的改变一下java.library.path的值。
    使用
    Java代码 复制代码
    1. System.setProperty("java.library.path", "./lib");  

    后,启动程序总是报错"no JIntellitype in java.library.path"

    想了半天没有想明白,为什么代码的设置就不起作用,而在虚拟机参数处指定就是好的?

    Google了半天才知道原因,这里整理一下,以方便以后查找。
    代码中设置不起作用,主要是因为java.library.path只在jvm启动时读取一次,其他情况下的修改不会起作用的。可以参考下面的这个bug:
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4280189

    原因和ClassLoader的实现有关系,
    ClassLoader.loadLibrary() method:
    Java代码 复制代码
    1. if (sys_paths == null) {  
    2.         usr_paths = initializePath("java.library.path");  
    3.         sys_paths = initializePath("sun.boot.library.path");  
    4. }  


    系统缓存了java.library.path的值,并且一直都会是第一次加载时的值。有人提到了下面的修改方法,
    Java代码 复制代码
    1. if (sys_paths == null) {  
    2.        sys_paths = initializePath("sun.boot.library.path");  
    3. }  
    4. usr_paths = initializePath("java.library.path");  

    但是从2002年到现在Sun一直都没有改,不知道出于什么原因考虑的。

    有问题,就会有人解决问题,antony_miguel在一篇文章中,使用java的反射机制,完成了对于ClassLoader类中的usr_paths变量的动态修改,
    Java代码 复制代码
    1. public static void addDir(String s) throws IOException {  
    2.     try {  
    3.         Field field = ClassLoader.class.getDeclaredField("usr_paths");  
    4.         field.setAccessible(true);  
    5.         String[] paths = (String[])field.get(null);  
    6.         for (int i = 0; i < paths.length; i++) {  
    7.             if (s.equals(paths[i])) {  
    8.                 return;  
    9.             }  
    10.         }  
    11.         String[] tmp = new String[paths.length+1];  
    12.         System.arraycopy(paths,0,tmp,0,paths.length);  
    13.         tmp[paths.length] = s;  
    14.         field.set(null,tmp);  
    15.     } catch (IllegalAccessException e) {  
    16.         throw new IOException("Failed to get permissions to set library path");  
    17.     } catch (NoSuchFieldException e) {  
    18.         throw new IOException("Failed to get field handle to set library path");  
    19.     }  
    20. }  

    文章也同时指出了这种实现的局限性,和jvm的实现强关联,只要jvm实现不是用的变量usr_paths来保存java.library.path的值,这个方法就不能用了。
    但是只要知道源代码,小小的改动就应该可以实现了。
  • 相关阅读:
    C#中 @ 的用法
    ASP.NET页面间传值
    ASP.NET中常用的文件上传下载方法
    把图片转换为字符
    把图片转换为字符
    JavaScript 时间延迟
    Using WSDLs in UCM 11g like you did in 10g
    The Definitive Guide to Stellent Content Server Development
    解决RedHat AS5 RPM安装包依赖问题
    在64位Windows 7上安装Oracle UCM 10gR3
  • 原文地址:https://www.cnblogs.com/diyunpeng/p/2245750.html
Copyright © 2011-2022 走看看