SWT3.3 M4(2006年12月15日)新增加的功能之一是自动加载原生库,特别是从SWT的Jar文件中加载原生库的功能,大大方便了我们发布基于SWT的Java程序。SWT是怎么实现这个功能的呢?  理解其中的原理后,您也可以在您自己的程序中实现类似的功能。
SWT负责加载原生库的方法是Library类的loadLibrary (String name)
static
 {
    Library.loadLibrary(
"
swt
"
);
}
Library.loadLibrary()做的第一件事在库名上加上版本号,比如swt-win32-3325。
如果您的原生库文件名不包含版本号,您可以省略这一步。
String version = System.getProperty ("swt.version"); 
if (version == null) {
    version = "" + MAJOR_VERSION; 
    /* Force 3 digits in minor version number */
if (MINOR_VERSION < 10) {
        version += "00"; //$NON-NLS-1$
    } else {
        if (MINOR_VERSION < 100) version += "0"; 
    }
    version += MINOR_VERSION;        
    /* No "r" until first revision */
if (REVISION > 0) version += "r" + REVISION; 
}
libName1 = name + "-" + Platform.PLATFORM + "-" + version;  
libName2 = name + "-" + Platform.PLATFORM
第二件事是加上操作系统相关的库扩展名,比如Windows的.dll, Unix/Linux的.so. 
调用System.mapLibraryName (libName1).
mappedName1 
=
 System.mapLibraryName (libName1);
mappedName2 
=
 System.mapLibraryName (libName2);
然后按顺序从swt.library.path和java.library.path指定的目录下寻找。如若没有成功,
并且没有设置swt.library.path,那么再找一下java.io.tmpdir指定的目录。要是还没有成功,Library将尝试
将SWT的Jar文件中的原生库解压到swt.library.path目录下或者java.io.tmpdir目录下。
/*
 Try loading library from java library path 
*/
f
 (load (libName1)) 
return
;
if
 (mapName 
&&
 load (libName2)) 
return
;
    
/*
 Try loading library from the tmp directory  if swt library path is not specified 
*/
if
 (path 
==
 
null
) {
        path 
=
 System.getProperty (
"
java.io.tmpdir
"
); 
        path 
=
 
new
 File (path).getAbsolutePath ();
        
if
 (load (path 
+
 SEPARATOR 
+
 mappedName1)) 
return
;
        
if
 (mapName 
&&
 load (path 
+
 SEPARATOR 
+
 mappedName2)) 
return
;
}
        
/*
 Try extracting and loading library from jar 
*/
if
 (path 
!=
 
null
) {
        
if
 (extract (path 
+
 SEPARATOR 
+
 mappedName1, mappedName1)) 
return
;
        
if
 (mapName 
&&
 extract (path 
+
 SEPARATOR 
+
 mappedName2, mappedName2)) 
return
;
}
    
/*
 Failed to find the library 
*/
throw new UnsatisfiedLinkError (
"
no 
"
 
+
 libName1 
+
 
"
 or 
"
 
+
 libName2
+
 
"
 in swt.library.path, java.libary.path or the jar file
"
);
extract (path+SEPARATOR+mappedName1, mappedName1)将mappedName1从Jar中解压到
path+SEPARATOR+mappedName1。最后如果还是没有成功,甩出一个UnsatisfiedLinkError。
整个过程有意思的只是extract()方法,下面来看看extract
static
 
boolean
 extract (String fileName, String mappedName) 
{
    FileOutputStream os 
=
 
null
;
    InputStream is 
=
 
null
;
    File file 
=
 
new
 File(fileName);
    
try
 
{
        
if
 (
!
file.exists ()) 
{
            is 
=
 Library.
class
.getResourceAsStream (
"
/
"
 
+
 mappedName);
            
if
 (is 
!=
 
null
) 
{
                
int
 read;
                
byte
 [] buffer 
=
 
new
 
byte
 [
4096
];
                os 
=
 
new
 FileOutputStream (fileName);
                
while
 ((read 
=
 is.read (buffer)) 
!=
 
-
1
) 
{
                    os.write(buffer, 
0
, read);
                }
                os.close ();
                is.close ();
                
if
 (
!
Platform.PLATFORM.equals (
"
win32
"
)) 
{
                    
try
 
{
                        Runtime.getRuntime ().exec (
                new
 String []
{
"
chmod
"
, 
"
755
"
, fileName}
).waitFor();
                    }
 
catch
 (Throwable e) 
{}
                }
                
if
 (load (fileName)) 
return
 
true
;
            }
        }
    }
 
catch
 (Throwable e) 
{
        
try
 
{
            
if
 (os 
!=
 
null
) os.close ();
        }
 
catch
 (IOException e1) 
{}
        
try
 
{
            
if
 (is 
!=
 
null
) is.close ();
        }
 
catch
 (IOException e1) 
{}
    }
    
if
 (file.exists ()) file.delete ();
    
return
 
false
;
}
Library.class.getResourceAsStream ("/" + mappedName)返回指向Jar根目录下mappedName文件的
InputStream.个人感觉,extract写得有点乱,if套着if,if套着try,当然并不是很糟糕,本身这是一个比较简单的函数。
在我自己的程序中,重写了extract(改名为extractAndLoad),相对来说要清爽一些,请大家比较。 
通过上面的分析,我们可以很简单实现我们自己的loadLibrary
import
 org.eclipse.swt.SWT;
import
 java.io.File;
import
 java.io.FileOutputStream;
import
 java.io.InputStream;
/**
 * The method loadLibrary load a native library in the order 
 * from java.library.path, os.library.path, tmpdir and from jar.
 *  
 * 
@author
 pan
 
*/
public
 
class
 Library {
    
static
 
final
 String SEPARATOR 
=
 System.getProperty(
"
file.separator
"
);
    
public
 
static
 
void
 loadLibrary(String name) {
        
//
 Try loading library from os library path
        String path 
=
 System.getProperty(
"
os.library.path
"
);
        
if
 (path 
!=
 
null
) {
            path 
=
 
new
 File(path).getAbsolutePath();
            
if
 (_load(System.mapLibraryName(path 
+
 SEPARATOR 
+
 name)))
                
return
;
        }
        
//
 Try loading library from java library path
        
if
 (_load(name))
            
return
;
        
//
 Try loading library from the tmp directory if os library path is not specified
        
if
 (path 
==
 
null
) {
            path 
=
 System.getProperty(
"
java.io.tmpdir
"
);
            path 
=
 
new
 File(path).getAbsolutePath();
            
if
 (_load(System.mapLibraryName(path 
+
 SEPARATOR 
+
 name)))
                
return
;
        }
        
//
 Try extracting and loading library from jar
        
if
 (path 
!=
 
null
                
&&
 loadFromJar(System.mapLibraryName(path 
+
 SEPARATOR 
+
 name),
                        System.mapLibraryName(name)))
            
return
;
        
//
 Failed to find the library
        
throw
 
new
 UnsatisfiedLinkError(
"
no 
"
 
+
 name
                
+
 
"
 in java.libary.path, os.library.path or jar file
"
);
    }
    
private
 
static
 
boolean
 _load(String libName) {
        
try
 {
            
if
 (libName.indexOf(SEPARATOR) 
!=
 
-
1
) {
                System.load(libName);
            } 
else
 {
                System.loadLibrary(libName);
            }
            
return
 
true
;
        } 
catch
 (UnsatisfiedLinkError e) {
        }
        
return
 
false
;
    }
    
private
 
static
 
boolean
 loadFromJar(String outFileName, String libName) {
        
try
 {
            
return
 extractAndLoad(outFileName, libName);
        } 
catch
 (Throwable e) {
        }
        
return
 
false
;
    }
    
private
 
static
 
boolean
 extractAndLoad(String outFileName, String libName)
            
throws
 Throwable {
        
int
 read;
        
byte
[] buf 
=
 
new
 
byte
[
4096
];
        InputStream is 
=
 
null
;
        FileOutputStream os 
=
 
null
;
        File file 
=
 
new
 File(outFileName);
        
if
 (file.exists())
            file.delete();
        
if
 (
!
file.exists()) {
            
try
 {
                os 
=
 
new
 FileOutputStream(file);
                is 
=
 Library.
class
.getResourceAsStream(
"
/
"
 
+
 libName);
                
if
 (is 
==
 
null
 
||
 os 
==
 
null
)
                    
return
 
false
;
                
while
 ((read 
=
 is.read(buf)) 
!=
 
-
1
)
                    os.write(buf, 
0
, read);
            } 
finally
 {
                
if
 (os 
!=
 
null
)
                    os.close();
                
if
 (is 
!=
 
null
)
                    is.close();
            }
            
if
 (
!
SWT.getPlatform().equals(
"
win32
"
)) {
                Runtime.getRuntime().exec(
                        
new
 String[] { 
"
chmod
"
, 
"
755
"
, outFileName }).waitFor();
            }
            
return
 _load(outFileName);
        }
        
return
 
false
;
    }
}
然后把您的原生库打在Jar里面,用Library.loadLibrary加载原生库,而不是System.loadLibrary,这样您就
把原生库隐藏在您的Jar里面了。
转载请保留
http://www.blogjava.net/xilaile/archive/2007/03/23/105706.html