什么是jni:jni是java native interface的缩写,是java平台的一部分,允许java代码和其他语言写的代码进行交互。
在本模块resource下面或者创建一个模块在resource下面创建目录native/linux/amd64下面放入libhs.so native/windows/amd64下面放入hyperscan.dll native/windows/x86下面放入hyperscan.dll或者在maven项目新建一个model直接将文件放入src目录下,调用的时候直接引入该模块即可。
其中linux代表是linux的jni文件位置,windows/amd64代表是64位的windows的jni文件位置,windows/x86代表32位的windows的jni文件位置
加载:其中(
Properties props=System.getProperties(); //获得系统属性集
String osName = props.getProperty( "os.name" ); //操作系统名称
String osArch = props.getProperty( "os.arch" ); //操作系统构架 (是amd64还是x86)
String osVersion = props.getProperty( "os.version" ); //操作系统版本 )
public class Hyperscan {
public static final String OSName = System.getProperty("os.name").toLowerCase();
public static final String ArchName = System.getProperty("os.arch");
public static final boolean IsWindows = OSName.indexOf("windows") > -1;
public static final boolean IsLinux = OSName.indexOf("linux") > -1;
public static final boolean IsMacOs = !IsWindows && !IsLinux;
public static final String sharedExt = getSharedExtName();
//方法中native是jni的标识
public static native int hsExpressionInfo(String express, int flags, PointerWrapper info, PointerWrapper error);
public static native void hsFreeExpressionInfo(PointerWrapper info);
public static native void hsFreeCompileError(PointerWrapper error);
public static native String hsGetErrorMessage(PointerWrapper error);
public static native int hsGetErrorExpress(PointerWrapper error);
public static native int hsCreateStringBuffer(final byte[] input, PointerWrapper pointer);
public static native void hsReleaseStringBuffer(final byte[] input, PointerWrapper pointer);
public static native int hsCompile(String express, int flags, int block, PointerWrapper platform,
PointerWrapper database, PointerWrapper error);
public static native int hsCompileMulti(String[] express, int[] flags, int[] ids, int size, int block,
PointerWrapper platform, PointerWrapper database, PointerWrapper error);
public static native int hsDeserializeDatabase(byte[] data, int off, int length, PointerWrapper database);
public static native int hsGetDatabaseSize(PointerWrapper database);
public static native byte[] hsGetDatabaseBuffer(PointerWrapper database);
public static native int hsGetDatabaseBuffer2(PointerWrapper database,byte[] data, int off, int length);
public static native void hsFreeDatabase(PointerWrapper database);
public static native int hsAllocScratch(PointerWrapper database, PointerWrapper scratch);
public static native void hsFreeScratch(PointerWrapper scratch);
public static native int hsScan(PointerWrapper database, PointerWrapper scratch, long textBuffer, int off, int length, HitCallback callback);
static {
loadEmbeddedLibrary();
}
/**
* 加载 native 库
* 因为库比较大,没有打包到资源中, 需要另行向使用者发布库文件(native 目录下的文件)
* @return
*/
private static boolean loadEmbeddedLibrary() {
String ext = getSharedExtName();
String name = getSoName();
StringBuilder path = new StringBuilder();
path.append("native/")
.append(getCurrentPlatformIdentifier())
.append('/')
.append(name)
.append(".")
.append(ext);
String nativePath = path.toString();
File filePath = new File(nativePath);
if (!filePath.exists()){
try(InputStream is = Hyperscan.class.getResourceAsStream("/"+nativePath)) {
if (is != null){
filePath.getParentFile().mkdirs();
Files.copy(is,Paths.get(filePath.getAbsolutePath()));
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
System.load(filePath.getAbsolutePath());
return true;
}catch(UnsatisfiedLinkError e) {
e.printStackTrace();
return false;
}
}
static String getCurrentPlatformIdentifier() {
String osName;
if(IsWindows)
osName = "windows";
else if(IsLinux) {
osName = "linux";
} else
osName = "darwin";
return osName + "/" + ArchName ;
}
static String getSoName() {
String name;
if(IsWindows)
name = "hyperscan";
else if(IsLinux) {
name = "libhs";
} else
name = "libhs";
return name ;
}
static String getSharedExtName() {
if(IsWindows)
return "dll";
if(IsLinux)
return "so";
return "dylib";
}
}
调用:
直接使用Hyperscan.hsCompile()进行调用
加载:
JDK 提供给了我们两个方法用于载入库文件,一个是 System.load(String filename) 方法,另一个是 System.loadLibrary(String libname) 方法
两个方法都是用来装载dll文件,不论是JNI库文件还是非JNI库文件。本地方法在被调用时都需要通过这两个方法之一将其加载至内存。
System.load
System.load 参数必须为库文件的绝对路径,可以是任意路径,例如:
System.load("C:\\Documents and Settings\\TestJNI.dll"); //Windows
System.load("/usr/lib/TestJNI.so"); //Linux
System.loadLibrary
System.loadLibrary 参数为库文件名,不包含库文件的扩展名。
System.loadLibrary ("TestJNI"); //加载Windows下的TestJNI.dll本地库
System.loadLibrary ("TestJNI"); //加载Linux下的libTestJNI.so本地库
注意:TestJNI.dll 或 libTestJNI.so 必须是在JVM属性java.library.path所指向的路径中。
注意:System.loadLibrary(String libname)和java.library.path变量对应的路经相关,此方法加载的文件必须是在java.library.path这一jvm变量所指向的路径中。
可以通过如下方法来获得该变量的值:
System.getProperty("java.library.path");
默认情况下,在Windows平台下,该值包含如下位置:
1)和jre相关的一些目录
2)程序当前目录
3)系统目录(system32)
4)系统环境变量path指定目录(tomcat里面)
设置java.library.path的路径
1.windows 下
(1): 设置classpath的路径即可,一般的动态链接库是放到c:/window/system32这个目录下。
(2): 也可以修改环境变量,增加动态链接库的地址。
(3): 开发时设置 eclipse的动态库的地址, 具体参见:
http://blog.csdn.net/ty564457881/article/details/7066423
2.linux下
需要设置系统变量LD_LIBRARY_PATH来添加java.library.path。
因为JVM启动时,会使用系统变量LD_LIBRARY_PATH的值来初始化java.library.path属性。
java.library.path默认值
-Djava.library.path 和 LD_LIBRARY_PATH的区别
如果使用 java -Djava.library.path=/jni/library/path 的方式设置的话,会覆盖默认值。其值为:
/jni/library/path
如果使用 export LD_LIBRARY_PATH=/jni/library/path的方式设置的话,会追加其值到默认值中。LD_LIBRARY_PATH的值会插入到JRE本地库之后,操作系统库文件目录之前。其值为:
$JAVA_HOME/jre/lib/i386/server:$JAVA_HOME/jre/lib/i386
:$JAVA_HOME/jre/../lib/i386:/jni/library/path:/usr/java/packages/lib/i386:/lib:/usr/lib