Applet使用Pack200 压缩
介绍
本文简要介绍了pack200的原理和使用过程,最后给出了一个applet应用的实例。
原理及介绍:
Java应用程序和applet支持Gzip和Pack200.两种格式的部署
HTTP 1.1 (RFC 2616)协议定义了HTTP的压缩格式,因此应用程序的Jar文件可以压缩为gzip,compress和deflate。
根据SDK/JRE 5.0版本的定义,JAVA web端可以执行HTTP 压缩,而java插件遵循RFC2616协议。支持的技术为gzip和pack200-gzip.
应用程序发送HTTP请求给服务器,一个HTTP请求有很多个属性。其中Accept-Encoding (AE)可以设置格式为gzip或pack200-gzip。
Server可以实现通过扩展名.pack.gz或.gz文件搜索到请求的Jar文件,并返回文件路径。Server可以根据发送的文件类型设置响应的header的Content-Encoding (CE)属性为pack200-gzip,gzip或者Null,设置Content-Type (CT)为application/Java-archive。因此,通过检查CE属性,客户端就能自动地还原成原始的jar文件。
图1:应用程序请求打包或压缩的jar文件
上面的例子表明,客户端通过设置AE=“pack200-gzip,gzip”来请求一个foo.jar文件,服务器搜索到foo.jar.pack.gz文件。然后设置CE为pack200-gzip,将其发送回去。
上面的例子表明,如果没有找到foo.jar.pack.gz,服务端会找fool.jar.gz,如果找到,会设为CE为gzip并返回文件fool.jar.gz。
上面的例子表明,如果foo.jar.pack.gz和fool.jar.gz都没有找到,服务端将返回foo.jar,CE不会设值或者设为NULL。
上面的例子表明,遗留系统(没有HTTP或Pack200 压缩)请求foo.jar,也能无缝地继续工作。因此,建议把foo.jar, foo.jar.gz和foo.jar.pack.gz都放到服务器上。
要实现上面的功能,只需要使用一个简单的servlet或者任何一个遵循HTTP1.1的web服务器的服务模块,由于压缩的开销很大,不建议在服务模块中执行此压缩。
Pack200的压缩
Pack200在压缩Java class大文件时效率很高,在jar包都是class文件并且较大时,可以惊人的达到压缩前的1/9大小。
它的特点是:
合并和分类class文件中持久的数据,并在压缩文件中共置。
去掉了多余的类的属性。
存储内部数据结构。
使用delta和变量长度编码。
二次压缩时使用最优的编码类型。
Pack200(unpack200)的基本命令在%JDK%/bin 目录下可以找到。Jdk类库中也可以方便的引用。
压缩
Packer packer=Pack200.newPacker();
OutputStream output=new BufferedOutputStream(new FileOutputStream(outfile));
packer.pack(new JarFile(jarFile), output);
output.close();
解压
Unpacker unpacker=Pack200.newUnpacker();
output=new JarOutputStream(new FileOutputStream(jarFile));
unpacker.unpack(pack200File, output);
output.close();
Pack200的使用步骤
1 重新打包jar文件,使签名后的压缩可以正确执行。
pack200 --repack HelloWorld.jar
2 使用密钥库myKeystor
签名
jarsigner -keystore myKeystore HelloWorld.jar ksrini
检查签名文件正常工作
jarsigner -verify HelloWorld.jar
确保jar包仍正常运行
java -jar HelloWorld.jar
3 .打包
pack200 HelloWorld.jar.pack.gz HelloWorld.jar
4解包
unpack200 HelloWorld.jar.pack.gz HelloT1.jar
5 检查jar包
jarsigner -verify HelloT1.jar
检查Java -jar HelloT1.jar
经过以上几步,压缩的HelloWorld.jar.pack.gz就可以拿去部署了。
Applet应用实例:
1 编写并执行sh script,生成pack.gz
#进入目录
cd $PWD
# 生成证书
keytool -genkey -alias scckey -keystore sccstore -validity 3650 -storepass 123456 -dname "CN=ssc,OU=ssc,O=ssc,L=sh,ST=sh,C=cn" -keypass 123456;
#对所有jar包执行签名和压缩
for i in `ls *.jar`
do
#执行pack和unpack操作
pack200 --repack $i
#签名
jarsigner -keystore sccstore -storepass 123456 -keypass 123456 $i scckey
#生成.pack.gz(后缀名须为.pack.gz)
pack200 $i.pack.gz $i
done
2.Applet中增加标签,给VM传递两个参数,只有客户端为1.6up10以上,才加载压缩的jar.pack.gz,否则会自动加载未压缩的.jar
<HTML>
...
<APPLET CODE="HelloWorld.class" WIDTH=150 HEIGHT=25>
<PARAM NAME = "cache_archive" VALUE = "TestMain.jar"/>
<PARAM NAME="java_arguments" VALUE="-Djnlp.packEnabled=true"/>
</APPLET>
...
</HTML>
(注:传递参数的值是“-Djnlp.packEnabled=true”,我就是缺了一个“-”,怎么调试都不成功。)
3,把新生成的*.jar.pack.gz和*.jar一同部署到服务器上。
4,获取.pack.gz的具体连接信息片段类似:
正在连接 https://localhost:8443/scc/archive/ TestMain.jar.pack.gz
network: 正在下载资源:https://localhost:8443/scc/archive/ TestMain.jar.pack.gz
内容长度:95,050
内容编码: pack200-gzip
查看applet的java高速缓存,可以看到解压后的jar包为TestMain.jar。
参考资料
1 http://docs.oracle.com/javase/1.5.0/docs/guide/deployment/deployment-guide/pack200.html
2 http://docs.oracle.com/javase/6/docs/technotes/guides/jweb/tools/pack200.html
3 http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/pack200.html