002、一探究竟:我們寫的Java代碼到底是如何運(yùn)行起來的?

一探究竟:
我們的Java代碼到底是如何運(yùn)行起來的?
本文是我們正式開始講解JVM的第一篇文章。
第一周我們不會(huì)講解太多過于深?yuàn)W的原理知識(shí),那樣會(huì)讓很多原本對(duì)JVM不太了解的同學(xué)難以平滑的入門。
第一周的內(nèi)容主要是高屋建瓴的把JVM運(yùn)行機(jī)制的整體脈絡(luò)梳理清楚,而很多原本對(duì)JVM就有一定了解的同學(xué),可以耐下心來,就當(dāng)做是復(fù)習(xí)梳理一下。
要研究JVM技術(shù),先得搞明白一個(gè)問題:
我們平時(shí)寫的Java代碼,到底是怎么運(yùn)行起來的?
針對(duì)這個(gè)問題,我們來一步一步的分析。
首先假設(shè)咱們寫好了一份Java代碼,那這份Java代碼中,是不是會(huì)包含很多的“.java”為后綴的代碼文件?
比如User.java,OrderService.java,CustomerManager.java
其實(shí)咱們Java程序員平時(shí)在Eclipse、Intellij IDEA等開發(fā)工具中,就有很多類似這樣的Java源代碼文件。
那么大家現(xiàn)在思考一下,當(dāng)我們寫好這些“.java”后綴的代碼文件之后,接下來你要部署到線上的機(jī)器上去運(yùn)行,你會(huì)怎么做?
一般來說,都是把代碼給打成“.jar”后綴的jar包,或者是“.war”后綴的war包,是不是?
然后呢,就是把你打包好的jar包或者是war包給放到線上機(jī)器去部署。
這個(gè)部署就有很多種途徑了,但是最基本的一種方式,就是通過Tomcat這類容器來部署代碼,也可以是你自己手動(dòng)通過“java”命令來運(yùn)行一個(gè)jar包中的代碼。
咱們先用下面這張圖,回憶一下這個(gè)順序。

但是實(shí)際上這里有一個(gè)非常關(guān)鍵的步驟,那就是“編譯”
也就是說,在我們寫好的“.java”代碼打包的過程中,一般就會(huì)把代碼編譯成“.class”后綴的字節(jié)碼文件,比如“User.class”,“Hello.class”,”Customer.class“。
然后這個(gè)“.class”后綴的字節(jié)碼文件,他才是可以被運(yùn)行起來的!
所以首先,無論大家對(duì)JVM機(jī)制是否熟悉,咱們都先來回顧一下這個(gè)編譯的過程,以及“.class”字節(jié)碼文件的概念。
來看看下圖,一起來感受一下:

接著我們可能就要思考下一個(gè)問題:
對(duì)于編譯好的這些“.class”字節(jié)碼,是怎么讓他們運(yùn)行起來的呢?
這個(gè)時(shí)候就需要使用諸如“java -jar”之類的命令來運(yùn)行我們寫好的代碼了。
此時(shí)一旦你采用“java”命令,實(shí)際上此時(shí)就會(huì)啟動(dòng)一個(gè)JVM進(jìn)程。
這個(gè)JVM就會(huì)來負(fù)責(zé)運(yùn)行這些“.class”字節(jié)碼文件,也就相當(dāng)于是負(fù)責(zé)運(yùn)行我們寫好的系統(tǒng)。
所以平時(shí)我們寫好的某個(gè)系統(tǒng)在一臺(tái)機(jī)器上部署的時(shí)候,你一旦啟動(dòng)這個(gè)系統(tǒng),其實(shí)就是啟動(dòng)了一個(gè)JVM,由它來負(fù)責(zé)運(yùn)行這臺(tái)機(jī)器上運(yùn)行的這個(gè)系統(tǒng)。
對(duì)這個(gè)概念,大家一定要先搞清楚。
我們還是用一張圖來展示一下,相信大家圖文結(jié)合,會(huì)理解的更好。

接著下一步,JVM要運(yùn)行這些“.class”字節(jié)碼文件中的代碼,那是不是首先得把這些“.class”文件中包含的各種類給加載進(jìn)來?
這些“.class”文件不就是我們寫好的一個(gè)一個(gè)的類嗎?對(duì)不對(duì)?
此時(shí)就會(huì)有一個(gè)“類加載器”的概念。
此時(shí)會(huì)采用類加載器把編譯好的那些“.class”字節(jié)碼文件給加載到JVM中,然后供后續(xù)代碼運(yùn)行來使用。
我們?cè)倏聪聢D。

接著,最后一步,JVM就會(huì)基于自己的字節(jié)碼執(zhí)行引擎,來執(zhí)行加載到內(nèi)存里的我們寫好的那些類了
比如你的代碼中有一個(gè)“main()”方法,那么JVM就會(huì)從這個(gè)“main()”方法開始執(zhí)行里面的代碼。
他需要哪個(gè)類的時(shí)候,就會(huì)使用類加載器來加載對(duì)應(yīng)的類,反正對(duì)應(yīng)的類就在“.class”文件中。
大家最后看看下面的圖。

好,最后我們來對(duì)本文小結(jié)一下:
無論是對(duì)JVM了解或者是不了解的同學(xué),我們都希望通過第一周的基本原理知識(shí)講解,降低學(xué)習(xí)后面JVM優(yōu)化實(shí)戰(zhàn)技術(shù)的門檻。
對(duì)于了解JVM的同學(xué)權(quán)當(dāng)復(fù)習(xí)梳理,而且鼓勵(lì)大家在底部評(píng)論發(fā)言,說說自己的理解和看法。
對(duì)于不太了解JVM的小白同學(xué),也可以抄底門檻迅速入門,無縫銜接后續(xù)的知識(shí)學(xué)習(xí)。
所以本文從我們平時(shí)寫“.java”后綴的源代碼開始,一步一步梳理了以下的流程:
寫好的代碼編譯成“.class”后綴的字節(jié)碼文件
JVM是個(gè)什么東西
JVM跟我們平時(shí)運(yùn)行在機(jī)器上的系統(tǒng)之間是什么關(guān)系
類加載器的概念
針對(duì)加載進(jìn)內(nèi)存的類進(jìn)行代碼的執(zhí)行
這就是本文講解的內(nèi)容總結(jié),希望大家對(duì)這部分內(nèi)容高屋建瓴的先有一個(gè)認(rèn)識(shí)。
另外,最后我給大家留一個(gè)思考題:既然“.java”文件可以編譯成“.class”文件再運(yùn)行,那么也肯定可以將“.class”文件反編譯成“.java”文件。
但是這樣的話,如果你們公司的系統(tǒng)代碼編譯好之后,都是“.class”的格式,但是被別人拿到了,反編譯回來不就可以竊取你們公司的核心系統(tǒng)的源代碼了?對(duì)這個(gè)問題,大家覺得應(yīng)該怎么解決呢?
大家可以思考思考,踴躍提問和發(fā)言,明天的文章里,在末尾我會(huì)跟大家探討一下這個(gè)問題。
End
版權(quán):公眾號(hào)儒猿技術(shù)窩
未經(jīng)許可不得傳播,如有侵權(quán)將追究法律責(zé)任