java 程序执行原理

摘要:
转移自:http://blog.csdn.net/walkingmanc/article/details/6369487java应用程序可以打包成jar格式。jar格式实际上是一种非常常见的压缩格式。与zip格式一样,它只将META-INF/MANIFEST添加到压缩文件MF元文件的目录结构中。我们知道,编译后的字节码类文件可以直接放入java虚拟机中进行解释和执行(JIT模式)

转自:http://blog.csdn.net/walkingmanc/article/details/6369487
java 应用可以打包成jar 格式, jar格式其实只是一种很普通的压缩格式,与zip格式一样,只不过是它会在压缩文件的目录结构中增加一个META-INF/ MANIFEST.MF 的元文件。

我们知道,经过编译的字节码class文件可以直接放到java虚拟机去解释执行(JIT方式), 我们通过在命令行调用“java class文件的路径”就可以使用jvm(java.exe/javaw.exe)来解释执行这些字节码文件。

我们知道,java源代码(.java文件)经过java编译器javac编译以后,会得到java的字节码的中间语言文件,也就是我们通常所说的类文件(.class文件),这些类文件会按照java源文件的包结构分目录存放,jar 命令的作用就是按照这种包目录结构打包这些字节码的class文件,形成一个jar包,并且增加一个META-INF/ MANIFEST.MF 的元文件 。这样打包的jar文件的确是包含了按照包目录结构存放的字节码class文件,但是这时候如果你在命令行:jar -jar a.jar 的话,会提示你指定一个主类,这是因为,虽然jar包里面包含了按照包目录结构存放的字节码class文件,但是却并不知道主类(含有 public static void main(String[])入口 方法的类)的位置,所以需要你手动的指定主类,然后才可以开始执行。

当然, 只需要在打包jar文件的时候,将主类的信息包含进去了以后,再:jar -jar a.jar 的话, 就不需要手动的指出主类是哪个类了。进行如下操作:

新建一个.mf文件,名字任意,例如:manifest.mf ,在里面指定主类是哪个类,即:写入一行 :Main-Class: test.Test。然后,打包: jar cvfm test.jar manifest.mf test; 这样打成的包test.jar里面就已经包含主类是哪个类的信息了。这样的话,在命令行里面直接执行:jar -jar test.jar 就可以运行该应用了,这种情况下, jvm会去这个class文件的包中寻找入口函数如何进入执行。

我们发布java应用的时候,直接发布按照包结构存放的class文件夹显然是很不方便的,一般需要打包成jar文件来发布。 就好象我们将java应用部署到tomcat web 服务器上去的时候一样, 虽然直接将按照包结构存放的class文件夹放过去是可以的,但是通常还是要打包成jar包的格式来部署,因为这样文件的数量会少,便于管理部署的。

将命令行的“java -jar jar文件的路径” 写到一个.bat文件里面 或者linux下面的shell文件里面,这样就可以通过执行.bat文件或者shell脚步来执行java 应用程序了,也就是说可以直接双击windows下的.bat文件或者linux下的.sh文件来运行java应用程序了。

一般在安装jre (Java Runtime Environment) 的时候,安装文件会将 .jar 文件映射给 javaw.exe 打开,如果没有关联,也可以手动的通过文件夹选项来手动关联,关联以后,当用户在windows下双击jar文件的时候,资源管理器就会调用javaw来运行该jar文件,这样就可以实现双击运行jar文件了。

jdk 相关过程原理分析。

我们知道,在jdk的bin目录下有很多的exe文件,例如java.exe, javac.exe, javadoc.exe等。 这些exe文件格式实质上是windows操作系统下的可执行文件格式(在dos下还有一种可执行可是是.com后缀的格式,不过现在已经不常见了),它们是由C语言写成的.c文件经过编译后生成的。例如:java.exe对应的源码就是java.c文件。java.c的main入口函数中会调用函数:CreateExecutionEnvironment,该函数中会查找jre路径,然后根据jvm.cfg配置文件配置的虚拟机动态链接库(jvm.dll)路径参数装载jvm.dll动态连接库,也就是加载java虚拟机(java虚拟机是C++写的,也有部分C代码),然后初始化jvm.dll(所有的dll都是本地语言写成的), 并挂接到JNIEnv(JNI调用接口)实例,最后调用JNIEnv实例装载并处理class类。
由上面的分析我们可以看到,windows操作系统下的exe文件大部分情况下是使用windows本地语言所写的代码编译而成的的,这些exe文件用于完成一定的功能,例如java.exe, 可以用来查找并加载jvm.dll ,然后通过调用jvm.dll 的 接口来加载java的字节码中间语言文件.class文件,并启动java应用程序。 或者完成其它的一些功能等。exe文件也可能是本地语言代码生成的exe文件与jar包压缩而成的。

更加方便的方法是,将jar做成exe。例如eclipse 就是一个java 应用程序,就采用了 使用exe来wrapper。

wrapper 基本原理: 在本地化语言(C或者C++等)代码中调用jvm.dll,然后通过jvm.dll提供的接口加载压缩在一起的jar包中的主类class的入口方法( static void main(String args[]), 从而启动java应用程序,这种加壳方式形成的java应用的exe文件在启动的时候会表现为一个exe进程,这种方式更常见。(形式是一个由本地化语言exe和jar包一起压缩而成的一个exe文件);

也可以在本地化语言(C或者C++等)代码中调用java.exe/javaw.exe进程(java.exe进程会执行前一种方法的步骤来完成jvm.dll的加载)来加载jvm.dll,然后通过jvm.dll提供的接口加载压缩在一起的jar包中的主类class的入口方法( static void main(String args[]), 从而启动java应用程序,这种加壳方式形成的java应用的exe文件在启动的时候会表现为一个exe进程和一个javaw进程。(形式是一个由本地化语言exe和jar包一起压缩而成的一个exe文件,当然,也可以选择不将jar文件和本地exe文件压缩在一起);

这两种根本上都是通过本地代码来加载java虚拟机,然后在本地代码中通过调用jvm.dll的接口来完成class主文件的加载和java应用的启动的。

具体来说,也有很多种方法。

可以使用c语言等本地语言创建一个本地代码(编译后生成exe文件),在该本地代码中加载jvm的动态库,并通过动态库的接口来在本进程内启动java虚拟机,即调用JNI_CreateJavaVM这个导出函数来创建Java虚拟机,得到JNIEnv指针,然后调用FindClass查找Main Class,之后调用GetStaticMethodID方法得到main方法,并执行main方法。 编译该本地代码得到一个exe文件。

将Java应用程序的class目录结构打包为jar文件,并与本地代码exe文件合并:在Dos提示符下执行copy命令:

C:/>copy test.exe+test.jar test.exe
其实,就是将Java打包文件追加到exe文件尾部。打开文件属性对话框,可看到有“压缩文件”属性页。
老牌的JBuilder.exe开发工具编译生成的exe文件即采用如下方式生成。
后记:大家在使用Eclipse 3.2和Eclipse 3.3时,在任务管理器中会看到二者的不同。
Eclipse 3.2是先启动Eclipse.exe文件,然后由Eclipse.exe启动Javaw.exe文件来创建虚拟机。
Eclipse 3.2在任务管理器中显示为Eclipse.exe和javaw.exe两个进程。
Eclipse 3.3在任务管理器中显示为Eclipse.exe一个进程。
从上面可以看出,Eclipse 3.2和Eclipse 3.3采用了不同的虚拟机加载方式。

Eclipse 3.2采用创建子进程的方法调用javaw.exe来启动,在windows下面可以用CreateProcess方法,此种方法较简单,具体可参见Eclipse源码。

Eclipse 3.3加载java虚拟机的另外一种方法是加载jvm的动态库,并通过动态库的接口来在本进程内启动java虚拟机。本文开头即采用的第二种方法。

写一个exe,调用java.exe来启动一个进程。
这很简单,启动vc,建一个win32 project,WinMain里使用ShellExecute函数即可,主要代码是:

#include "stdafx.h"
#include "resource.h"

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
ShellExecute(NULL,"open",".//jre6//bin//javaw.exe","-ea -Dfile.encoding=GB18030 -Xmx600M -splash:res//splash.png -classpath /"./lib/*/" com.zms.laser.uis.Starter",".//",SW_SHOWNORMAL);
return 0;
}
要给编译出来的可执行程序一个图标,很简单,只要添加一个icon的资源,让这个icon的id最小即可。编译器会把具有最小id的icon当作最终exe的图标。

所有的给java 应用 加 exe 外壳的 工具软件 采用的都是以上原理中的一种。

免责声明:文章转载自《java 程序执行原理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Flask-Migrate的使用和常见"坑"的解决办法技嘉主板开启快速启动后无法进入BIOS的简单解决方法。下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Mac-VM迁移注意事项

1.迁移之后首先查看mac的网关是多少: 先cd /Library/Preferences/VMware Fusion/vmnet8 然后 cat nat.conf ip 172.16.190.2就是我的网关,你的和我的应该不一致 2.配置虚拟机中的网络 点击系统-首选项-网络连接。 配置你的网卡,我的是eth1. 地址就是你的这台虚拟机ip,网关和dn...

windows内核开发环境的简易搭建

一、windows内核开发需要的软件 1.WDK 2.WinDbg 3.virtualKD 4.DebugView 5.Visual C++ 6.0 6.VMware Workstation 二、windows内核开发软件的安装 1.WDK的安装和配置 wdk的下载地址:http://download.microsoft.com/download/...

VMware 虚拟机网络 组网问题

1.VMware虚拟机组网概述       整个结构:                      需要确定的内容:      1) 虚拟机连接到哪个VMnet(交换机)?      2) VMnet(交换机)的组网模式? 首先,讲一下VMware的界面内容       安装好VMware虚拟机后,启动后,点击编辑,找到虚拟网络编辑器            ...

HyperV应用指南之5-导出、导入虚拟机[转]

 导出、导入虚拟机 使用一个设置好的“模板”虚拟机创建多个相同的备份,有两种方法,一种是将选定的虚拟机“导出”然后再改名“导入”,这种方法创建的虚拟机与原虚拟机完全一样,包括占用的硬盘空间大小都相同;另一种是以“模板”虚拟机为基准,使用“差异”磁盘创建多个虚拟机,新创建的虚拟机“依附”模板虚拟机的磁盘,而新虚拟机的改动将只反映在新创建的“差异”磁盘中,并占...

第15章-解释器及解释器生成器

方法解释执行时需要解释器与解释器生成器的支持。解释器与解释器生成器的继承体系如下: 下面详细介绍解释器与解释器生成器。 1、解释器 解释器是一堆本地代码例程构造的,这些例程会在虚拟机启动的时候写入到StubQueue中,以后解释执行时就只需要进入指定例程即可。 解释器的继承体系如下: AbstractInterpreter /interpr...

虚拟机自动获取ip//脚本修改ip和主机名

目录 网卡的启动协议 初始网卡配置文件 使用脚本修改IP 和 主机名 网卡的启动协议 # wangka启动协议 BOOTPROTO="none" - none # 没有协议 - static # 静态协议(手动设置IP) - dhcp # 动态协议(自动获取IP) # 编辑wangka 配置文件 [root@web02 ~]# vim /e...