Java程序的执行流程

首先一个java程序,先会被被编译成. class文件,然后程序会被加载到JVM中,进行连接,接着就会被初始化。下面是相关流程:

1.将.java文件编译成.class文件。编译之后的文件,可以通过javap -c xxx.class看到反汇编的文件中,里面一开始会看到jvm默认会有一个无参构造函数,同时相关的jvm虚指令信息。比如iconst常量信息。

2.加载的过程中,JVM会读取class文件。类加载过程中主要包括:将class文件读取到运行时方法区内,在堆中创建class对象,并封装类在方法区内。期间,读取的文件既可以通过文件方式,也可以通过jar包、war包甚至代理自动生成的方式。

3. 加载完之后,会进行连接,而连接的过程又分为验证、准备、解析。
(1)验证的过程:检查当前的class文件是否符合jvm要求,比如魔数:每个class文件的前四个字节表示魔数ca fe ba be。
(2)准备:在方法区中为类变量分配内存空间,并设置类中变量的初始值。注意非final和final类型的变量。其中非final的变量,比如Int采用默认值为0,而赋值的过程是在初始化的过程中完成的。而final的变量在编译阶段ConstantValue就有值了,因此此时的值就是给的值。
(3)解析:会将常量池中的符合引用替换成直接引用。

4. 初始化
主要通过执行类构造器的<client>方法为类进行初始化,而<client>分为父子类的<client>方法,<client>方法是在编译阶段由编译器自动收集类中的静态语句块和变量的赋值操作。

在加载过程中,有几类加载器:
(1)系统级别的:启动类加载器,加载java/lib下的类库
(2)扩展级别的:扩展类加载器,加载java/lib/ext下的类库
(3)应用级别的:应用程序类加载器,加载classpath下的类库
(4)自定义的:自定义加载器,加载自己定义路径下的类库

而对类的加载,采用双亲委派模式,从委派我们可以知道不是自己亲力亲为的,委托自己的父类对类进行加载,如果父类无法加载,则会反馈给子类进行加载。委派模式在Spring源码中是非常常见的。

双亲委派模式保证了类的唯一性和安全性。也就是说如果包含相同类包下和类名的两个类,它是无法加载的。
而在Tomcat和OSGI中,是不再遵守双亲委模式的。我们知道Tomcat可以加载多个war包,同时可以启动运行的,此时加载的系统类加载器和扩展类加载器是一样的,同时实现了自己的类加载器,在tomcat的WEN-INF中,可以看到CommonClassLoader、CatalinaClassLoader、SharedClassLoader、WebappClassLoader ,而CommonClassLoader是CatalinaClassLoader、SharedClassLoader的公共库,可以被它们俩调用 但是两者之间又是隔离的。同时SharedClassLoader可以被WebappClassLoader调用。而WebappClassLoader之间又是隔离的。而CommonClassLoader想要调用WebappClassLoader,则采用线程上下文类加载器实现,使用线程上下文加载器,可以让父类加载器请求子类加载器去完成类加载的动作。

OSGI面向服务的一种架构,实现动态模块加载,实现部分服务的动态更新。其不再遵守双亲委派模式。

原创文章,作者:pi,如若转载,请注明出处:https://pi.do/55.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注