JNI技术中本地代码的加载与卸载

来源:互联网 发布:java常用英语代码 编辑:程序博客网 时间:2024/05/05 15:32
JNI技术中本地代码的加载与卸载

      JNI指的是“JAVA本地调用接口”。通过这种技术JAVA可以调用由其它语言(包括C++)为JAVA编写的本地代码。在Windows上这可能是DLL,在Linux上则可能是一个SO。
我的这个实验是在Windows上通过的,所以我所指的本地代码是一个DLL动态链接库。

一、实现JNI

1)先编写一个Main.java文件如下。

class Main{
 public static native void hello();

        public static void main(String args[])
        {
           System.load("C://T.DLL");

            hello();
  
        }
}

 

解释:其中以native修饰的hello函数就是一个本地调用接口,它没有函数体因为函数体在我将要生成的T.DLL中。main函数是Main类的入口首先它加载T.DLL然后调用其中的hello函数,就这么简单!
2)编译Main.java

   命令:javac Main.java

解释:如果没有问题这时已生成了Main.class文件,对JAVA来讲这是一个编译后的可执行文件。
  
3)生成本地代码库————“T.DLL”

   3.1) 生成C++头文件————“Main.h”

      命令:javah Main
  解释:如果没有问题这时已生成了“Main.h”文件,我生成的文件内容如下,注意其中对Java_Main_hello函数的声明,这就是JAVA中的helllo函数

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */

#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Main
 * Method:    hello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Main_hello
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

 

    3.2)用VC生成一个DLL工程,我的主要程序文件如下,注意对Java_Main_hello函数的实现

// T.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"


#ifdef _MANAGED
#pragma managed(push, off)
#endif
#include "Main.h"
JNIEXPORT void JNICALL Java_Main_hello(JNIEnv *, jclass)
{
 MessageBox(0,L"hello",L"你用过HL脚本语言吗?",MB_OK);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

 

     3.3)编译C++工程生成T.DLL,并拷贝到C盘根目录下。


4)执行Main.class
命令:java Main
解释:如果没有问题这时已看到了弹出的MessageBox

二、卸载本地代码库


       如果照上面那样当Main执行完了进程就退出了,自然T.DLL也就卸载了。但是实际的应用中会遇到进程还要继续而必须卸载T.DLL的时候。终于我在网上找到了这样的方法,拿来与大家分享!

1)修改Main类代码,新的Main.java文件内容如下,注意与开始时的不同之外(尤其注意unloadNativeLibs函数)

import java.util.*;
import java.lang.reflect.*;

class Main{

 public static native void hello();

 private void unloadNativeLibs() throws Throwable {

  ClassLoader classLoader = this.getClass().getClassLoader();
  Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
  field.setAccessible(true);
  Vector libs = (Vector) field.get(classLoader);
  Iterator it=libs.iterator();
  Object o;
  while(it.hasNext())
  {
   o=it.next();
   Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]);
   finalize.setAccessible(true);
   finalize.invoke(o, new Object[0]);
    
  }
 }
 public boolean freeLibrary(){
  boolean result=true;
  try{
   unloadNativeLibs();
  }catch(Throwable e){
   result=false;
  }
  return result;
 }

        public static void main(String args[])
        {
  System.load("C://T.DLL");

 
  hello();
  new Main().freeLibrary();
  int i=0;
  for(i=0;i<10000;i++)
  {
   System.gc();
  }
        }
}

 

解释:在main函数中当().freeLibrary调用之后,程序开始了一个长时间的循环,在这个循环进行的过程中进程没有退出,但我可以删除T.DLL了,这表示它已被卸载了。
 
原创粉丝点击