使用C程序调用Java类方法

首先创建一个Java类,这里的示例是一个链接HBase的Java小程序:

import java.io.IOException;         
import org.apache.hadoop.conf.Configuration;     
import org.apache.hadoop.hbase.HBaseConfiguration;     
import org.apache.hadoop.hbase.HColumnDescriptor;     
import org.apache.hadoop.hbase.HTableDescriptor;     
import org.apache.hadoop.hbase.KeyValue;         
import org.apache.hadoop.hbase.client.Get;     
import org.apache.hadoop.hbase.client.HBaseAdmin;     
import org.apache.hadoop.hbase.client.HTable;     
import org.apache.hadoop.hbase.client.Result;     
import org.apache.hadoop.hbase.client.ResultScanner;     
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Put;  
import org.apache.hadoop.hbase.util.Bytes; 
public class Connect {
	public Connect(){
	super();	
}
   	public static Configuration conf =null;
        static {  
        conf = HBaseConfiguration.create();
    } 
    
    /**   
     * 创建一张表   
     */    
	public static void createTable() throws Exception {
	String tableName="sensor";
	String[] familys={"ID", "state"};	  
        HBaseAdmin admin = new HBaseAdmin(conf);  
        if (admin.tableExists(tableName)) {     
            System.out.println("table already exists!");     
        } else {    
            HTableDescriptor tableDesc = new HTableDescriptor(tableName);     
            
		for(int i=0; i<familys.length; i++){     
                tableDesc.addFamily(new HColumnDescriptor(familys[i]));     
            }     
            admin.createTable(tableDesc);     
            System.out.println("create table " + tableName + " ok.");     
        }      
    }
     /**   
     * 查找一行记录   
     */    
	public static String getOneRecord (String tableName, String rowKey) throws IOException{     
        HTable table = new HTable(conf, tableName);     
        Get get = new Get(rowKey.getBytes());     
        Result rs = table.get(get);     
        for(KeyValue kv : rs.raw()){     
            System.out.print(new String(kv.getRow()) + " " );     
            System.out.print(new String(kv.getFamily()) + ":" );     
            System.out.print(new String(kv.getQualifier()) + " " );     
            System.out.print(kv.getTimestamp() + " " );     
            System.out.println(new String(kv.getValue()));    return new String(kv.getValue());  
        }    
	return "0"; 
    }     
          
    /**   
     * 显示所有数据   
     */    
	public static void getAllRecord (String tableName) {     
        try{     
			HTable table = new HTable(conf, tableName);     
             Scan s = new Scan();     
             ResultScanner ss = table.getScanner(s);     
             for(Result r:ss){     
                 for(KeyValue kv : r.raw()){     
                    System.out.print(new String(kv.getRow()) + " ");     
                    System.out.print(new String(kv.getFamily()) + ":");     
                    System.out.print(new String(kv.getQualifier()) + " ");     
                    System.out.print(kv.getTimestamp() + " ");     
                    System.out.println(new String(kv.getValue()));   
                 }     
             }     
        } catch (IOException e){     
            e.printStackTrace();     
        }     
    }   

	/**   
         * 插入一行记录   
         */    
        public static void addRecord (String rowKey, String family, String value)     
                throws Exception{     
            try {
		String tableName ="sensor";    
		String qualifier="";
                HTable table = new HTable(conf, tableName);     
                Put put = new Put(Bytes.toBytes(rowKey));     
                put.add(Bytes.toBytes(family),Bytes.toBytes(qualifier),Bytes.toBytes(value));     
                table.put(put);     
                System.out.println("insert " + family+ " to table " + tableName +" ok.");     
            } catch (IOException e) {     
                e.printStackTrace();     
            }     
        } 
    public static void main(String[] args)
	{ try
		{Connect.addRecord("1","sequence","629");}
	  catch(Exception e)
		{}	
	}
    
}

创建完Java类后,就是怎么去使用C程序调用该类的问题。

首先引用<jni.h>头文件,该文件一般在JAVA_HOME/include目录下,利用该文件提供的函数使用JNI来建立java runtime environment。

然后,根据JavaVMOption和JavaVMInitArgs创建JavaVM虚拟机类型的指针,使用JNIEnv虚拟机环境类型变量指定类的加载路径。

接着,在找到加载类之后,选择调用的方法,这里调用的都是类方法,无须建立对象,库中已提供相应的接口GetStaticMethodID。

最后,结束时选择DestroyJavaVM方法删除JVM环境。

具体代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<mysql.h>
#include<time.h>
#include<sys/sem.h>
#include<fcntl.h>
#include<netinet/tcp.h>
#include <assert.h>
#include <jni.h>
jstring stoJstring(JNIEnv* env, const char* pat)
{
	jclass strClass = (*env)->FindClass(env,"java/lang/String");
	jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");
	jbyteArray bytes = (*env)->NewByteArray(env,strlen(pat));
	(*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat);
	jstring encoding = (*env)->NewStringUTF(env,"utf-8");
	return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);
}

 


char* jstringTostring(JNIEnv* env, jstring jstr)
{
	char* rtn = NULL;
	jclass clsstring = (*env)->FindClass(env,"java/lang/String");
	jstring strencode = (*env)->NewStringUTF(env,"utf-8");
	jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
	jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr, mid, strencode);
	jsize alen = (*env)->GetArrayLength(env,barr);
	jbyte * ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
	if(alen > 0){
		rtn = (char*)malloc(alen + 1);
		memcpy(rtn, ba, alen);
		rtn[alen] = 0;
	}
	(*env)->ReleaseByteArrayElements(env,barr, ba, 0);
	return rtn;
}
 



int main(int argc, char** argv)
{
	JavaVMOption options[2];
	JNIEnv *env;
	JavaVM *jvm;
	JavaVMInitArgs vm_args;
	long status;
	jclass cls;
	jmethodID mid;
	jboolean jnot;
	jobject jobj;

	options[0].optionString = "-Djava.compiler=NONE";
	options[1].optionString = "-Djava.class.path=.";
	//options[2].optionString = "-verbose:jni"; //用于跟踪运行时的信息

	vm_args.version = JNI_VERSION_1_4; // JDK版本号
	vm_args.nOptions = 2;
	vm_args.options = options;
	vm_args.ignoreUnrecognized = JNI_TRUE;
	
	while(1)
	{			
		if((childpid=fork()) == 0)
		{
			status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
			if(status != JNI_ERR){
				printf("create java jvm success\n");
				cls = (*env)->FindClass(env,"Connect");  // 在这里查找java类
				if(cls !=0){
					printf("find java class success\n");
					mid = (*env)->GetStaticMethodID(env, cls, "addRecord", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
					exit(0);}
				else{
					printf("Find Class failed\n");
				}
				(*jvm)->DestroyJavaVM(jvm);
				printf( "Java VM destory\n");
		
			}
			else{
				printf("create java jvm fail\n");
			}
		}
	}	
	return 0;
}






几个需要注意的问题:
1. 编译语句需指定头文件路径,否则会找不到。 g++ -o testjava testjava.cpp -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -L${JRE_HOME}/lib/i386/client -ljvm

2. JRE_HOME和LD_LIBRARY_PATH要设置好,编译C++程序时要使用JRE_HOME下面的libjvm.so动态库(一开始我使用网上说的使用JAVA_HOME目录下的libjvm.so,结果出现下面错误

# An unexpected error has been detected by HotSpot Virtual Machine:
#
 SIGSEGV (0xb) at pc=0xb6d3dbe3, pid=14454, tid=2773482416

#
# Java VM: Java HotSpot(TM) Server VM (1.5.0_11-b03 mixed mode)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值