JNI原理
先不讲JNI的原理,我们先来解析一下JDK是如何加载系统的库的。Windows上是动态连接库dll文件,在Linux是so文件。
系统库的加载
这里我们举一个例子深入研究一下,这样才能更清楚JDK到底做了哪些事情,我们看一下InetAddress类的静态块中有,
AccessController.doPrivileged(new LoadLibraryAction("net"));
这段代码的意思是加载net系统库,关于操作系统的系统库管理,可以查看相应的文档这里不介绍。AccessController.doPrivileged方法是不管权限都执行Action中的run方法,并将其返回值作为返回值。下面我们来看看LoadLibraryAction类,发现这个类是定义在rt.jar包中,查看代码后发现就是调用了System.loadLibrary(this.theLib);
. 其中thelib就是字符串net。
下面我们来看一下System.loadLibrary这个方法:
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
}
Runtime可以认为是系统运行的环境信息载体,不能被程序实例化,getRuntime就是取得唯一的那个实例,我们看一下loadLibrary0方法。
synchronized void loadLibrary0(Class fromClass, String libname) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(libname);
}
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: " + libname);
}
ClassLoader.loadLibrary(fromClass, libname, false);
}
关于安全检查的部分暂时跳过,后面我会来讲这部分的知识。然后我们可以发现,使用了ClassLoader.loadLibrary方法。这里面的代码很多,这里就不贴了,只是简单地讲解一下各部分是如何工作的而已。
我们发现在类中有两个属性usr_paths和sys_paths这两个数组属性,这两个属性的值来源于系统属性"java.library.path"和"sun.boot.library.path"当然如果是绝对地址,直接加载,当然啦,从System调用过来的不可能是绝对地址,直接调用了类加载器的findLibrary(name);方法来找相应的库。当时这个方法在ClassLoader中是返回空的,我不知道系统内实现的类加载器如何处理这个方法,但是如果我们想实现自己的功能,我觉得定义类加载器并且实现这个接口将会是十分有用的。然后就是在sys_paths中找,找到返回;最后才在user_paths中找。
找到之后生成对应的File,传入ClassLoader.loadLibrary0方法,这个方法又调用ClassLoader.loadLibrary1方法,这才是真正的加载函数。最后里面做了一大堆的验证和同步,其实有用的代码就一行NativeLibrary lib = new NativeLibrary(fromClass, name);
;这个NativeLibrary类就是最终的结果。它是ClassLoader的内部类。
NativeLibrary里面有jniVersion这个系统库的唯一标识符,可以通过这个表示符找到这个库。它的真正加载过程load函数是一个本地函数。这里的Native方法的本地库是什么时候被加载额呢?这个暂时还不知道,可能要读vm的源码才会有相应的答案。
关于改写加载路径的方法,除了设置user_paths的属性,还可以通过反射的方式改掉ClassLoader类的user_paths属性,这样也就实现了自定义用户的库加载。具体说明: http://blog.csdn.net/hjxhjh/article/details/9901215
这就是classLoader加载类库的主要过程。所有的加载类库是放在ClassLoader的private Vector<NativeLibrary> nativeLibraries = new Vector<>();
中,当然你可以认为这是预加载,其实确实是没有加载。关于什么时候加载和如何使用,需要结合JNI的学习。
JNI使用
待续
JNI原理剖析
待续