《碼農翻身》之Java帝國
這位大俠,這是我的公眾號:程式設計師江湖。
分享程式設計師面試與技術的那些事。 乾貨滿滿,關注就送。
《碼農翻身》讀書筆記之Java帝國
Java帝國(Java語言發展,JVM和class,持久化和IO,JDBC與DP,JTA與分散式事務,JSP與servlet等等內容)
這是我的後端讀書筆記系列文章的第二篇,選取的是最近剛剛圈粉的知名博主劉欣創作的《碼農翻身》。這篇文章只是第一部分。
本文內容主要根據知名博主劉欣一作《碼農翻身》的內容總結而來,本書的內容風趣幽默,講解計算機理論原理也是十分透徹,由於書中常常以小故事的形式出現,為了方便學習和回顧,我把它們進行了一些改編和整理,便於自己和跟多人閱讀。
本篇文章主要講述的書中的第二章“Java帝國”。
Java帝國的誕生
c語言誕生:
1995年時,c語言已經誕生了20年,統治了程式設計界,它貼近硬體執行極快,效率高,Linux也是使用c語言編寫的。
程式設計師們用c開發了很多系統級軟體,作業系統,資料庫,編譯期等等,正是因為它與底層接近,提供了記憶體管理和指標的特性,讓這些程式的執行效率很高。
c語言弊病:
但是c語言的記憶體管理和指標確是程式設計師的枷鎖,程式設計師必須手動釋放記憶體,並且操作指標時不會有越界提醒,於是執行時會暴露很多問題,程式設計師需要花大量時間處理指標和記憶體分配。
C語言由於貼近底層,在跨平臺方面很差勁,容易產生不相容的情況,而且必須使用c++標準庫,否則容易出問題。c++在c語言的基礎上出現,提供了面向物件的特性,讓企業級開發得心應手。但是他的特性非常複雜,學習難度很大。
Java誕生:
於是Java出現了。他支援跨平臺的執行,不用考慮記憶體管理和指標,也支援面向物件。Java程式必須執行在虛擬機器上,這個虛擬機器提供了一層抽象,它本身也是c語言編寫,用於真正和作業系統互動,但是對於程式設計師來說是透明的,更加友好和易於掌握。
Java發展:
Java帝國推出了J2SE,J2ME,J2EE三個類別的應用,J2SE主打applet,由於要求瀏覽器執行jvm,所以被早早淘汰,J2ME沒有等到移動網際網路到來就草草收場。
J2EE支援的是企業級開發,執行在伺服器上,支援很多大型專案需要的特性,於是weblogic和websphere等伺服器藉著J2EE大熱了一把。
帝國版圖:
構建構建:maven和ant
應用伺服器:Tomcat,jetty,jboss等
開發工具。。等等。
.NET,ruby和php等語言都難以撼動Java的地位。
Android出現後也改變了移動端。
Hadoop等大資料技術也採用Java。
我是一個Java class
類載入
1 Java class是一個位元組碼檔案,本質上是0101的位元組流。
JVM會使用類載入器載入這些class檔案,並且進行驗證(按照class格式檢查),解析,載入,初始化等過程,然後在堆中生成一個對應的Class物件。
2 載入一個類時,需要遵循雙親委派模型,先讓父類載入器檢查是否能載入該類,如果可以的話,就由父類載入器進行載入,否則依次往下詢問即可。
因為有個黑客寫過一個String類植入漏洞程式碼,讓自定義載入器載入他,導致問題。所以我們需要雙親委派載入模型。
當然父類載入器的權利比較大,一般載入的是lib下面的類,擴充套件載入器則載入lib\ext下面的類,其餘的類就由appclassloader根據classpath(自定義類輸出目錄)目錄來載入了。
jvm記憶體模型和GC
1 JVM把記憶體分成多個邏輯區域,方法區用來儲存類的元資料,堆區中儲存類的物件。每當執行緒操作方法時要先新建一個棧幀壓入虛擬機器棧(每個執行緒獨有的棧)中。棧幀裡又會有區域性變量表和運算元棧。
2 GC垃圾回收負責回收無用的物件,通過可達性分析標記和GC Root相連的物件,清理其他物件。
3 實際上Java程式碼是儲存在專案目錄下的,而編譯時會把Java程式碼編譯成class檔案並放到classpath目錄下,然後才能執行,編譯一般通過javac命令完成,執行class檔案或者jar包一般需要指定入口方法,比如main函式。
Java的持久化大法
1 Java執行在記憶體中,斷電時自然丟失資料結束執行,所以必須要有一些持久化方案來儲存資料。Java IO可以把物件轉儲成二進位制檔案,放到硬碟中,也就是序列化,然後需要的時候再反序列化還原即可。
2 使用資料庫進行持久化:
資料庫可以轉儲資料,並且把Java中的物件按照表格資料的形式進行轉儲,但是手動地進行轉換操作顯然需要大量程式碼。於是後來出現了ORM框架,簡化了這一對映過程。
要讓Java使用資料庫,那麼就必須先和資料庫通訊,當然也需要基於socket開發,和資料庫協商協議,然後建立TCP連線,最後完成通訊。JDBC完成了這個使命。
ORM框架
1 J2EE拿出了EJB作為企業級的伺服器中介軟體,並且把安全,事務,分散式,以及ORM的特性都糅合進去。但是卻十分低效。
orm框架hibernate出現了,專注於物件到資料庫的對映。而ibatis出現以後,更是可以方便地採用sql和對映兩種方式完成orm。
2 Spring出現以後逐漸取代EJB提供了更加輕量級的企業級開發特性,並且使用jdbctemplate集成了hibernate和ibatis等持久化框架。
JDBC的誕生
早期connection
MySQL其實已經定義好了應用層協議,一般都會開啟3306埠進行監聽,以便接收TCP請求。
然而,如果直接基於socket進行通訊,顯然是不合適的,所以JDBC抽象出一個叫做connection的類,來表示一個MySQL的資料庫連線。同時,使用statement表示sql的執行實體類,又用resultset表示查詢結果集。
由於Connection應該由不同的資料庫分別提供,所以connection只是介面,實現類要由mysql等資料庫提供jar包。
connection的封裝之路
寫死實現類:
由於資料庫提供了connection實現類,我們在程式碼裡也可以寫死實現類。但是一旦jar包更新,它的類名改變,那我們的程式碼編譯也會出錯。這樣看來我們不應該直接進行例項化。
簡單工廠:
不直接例項化,那麼可以考慮使用簡單工廠,我們把這個工廠叫做Driver,讓工廠給我們一個connection例項,根據傳入引數工廠會返回給我們對應的例項。
基於配置檔案進行反射的簡單工廠:
使用上述方案顯然會有問題,當我們需要增加其他資料庫的支援時,就必須要更改程式碼。為了解決這個問題,我們改變之前向工廠傳遞引數的策略,改用配置檔案的方式,把connection實現類的全限定名配置到配置檔案中。
由於有了類的全限定名,工廠中只需要進行反射呼叫完成例項化,即使有新的類要支援,也只需修改配置檔案即可。
工廠方法實現:
上述方法雖然可行,但是使用者在使用時必須要提供一個配置檔案,並且配置檔案中要有類的全限定名,這很低階。還有一點就是建立實現類的過程不應該被暴露出來,使用者只需要得到connection例項即可。
於是我們可以用工廠方法來實現,每個資料庫提供一個Driver實現類來實現Driver介面需要提供getconnection方法,封裝實現細節。使用者首先載入Driver實現類,再通過反射獲取driver例項,從而獲取connection。這樣子避免使用配置檔案並且封裝細節。
drivermanager靜態方法實現:
其實上面這個方案基本ok了。只不過要求使用者必須懂反射。更加人性化的方式是使用一個drivermanager類來管理所有的Driver實現類,通過一個集合來管理已註冊的Driver實現類,通過輸入引數來獲取指定Driver工廠生產的connection例項。
使用者需訪問drivermanager的靜態方法getconnection就可以獲取connection例項了。使用者先使用class.forname載入對應的driver,再通過上述方法獲取connection例項即可,不依賴於具體實現類,主要匯入包,執行方法即可,是最優雅的實現。
Java帝國之宮廷內鬥
本地事務:
DBC支援事務,預設的實現就自動開啟事務,執行提交操作時才會提交事務。但是事實上,JDBC支援的事務是本地事務,當遇到多個數據庫的問題時,就可能產生分散式事務的問題。
比如說A轉賬給B,A和B的資料分別在A庫和B庫,於是對A扣款和對B加款兩個操作分別是兩個事務,如何把保證兩個事務合為一個事務的原子性,就需要使用分散式事務。
全域性事務管理器和分散式事務:
2PC是一種分散式事務的解決方案,首先我們設定一個全域性事務管理器來協調各個資料庫的事務提交,全域性事務管理向各個資料庫發出準備訊息,各個資料庫準備好,鎖資源,維護日誌,執行操作但是不提交。
當全域性事務管理器得到所有資料庫執行成功的訊息之後才會通知每個事務提交,如有一個失敗則通知回滾。
顯然全域性事務管理器要負責和每個資料庫通訊。但事實上,2PC存在兩個問題,一是全域性事務管理器的宕機問題,另一個是資料庫的宕機問題。
JTA的事務實現
基於全域性事務管理的JTA實現只需要開啟一個全域性事務,然後執行每個資料庫的操作,最後進行提交,如果丟擲異常時則進行回滾,用起來也確實很方便。
但是全域性事務的實現雖然保證了強一致性,但是效能不好,因為經常需要鎖資源,並且需要消耗多節點的通訊時間。
最終一致性方案:訊息佇列實現
事實上不需要使用2PC的分散式事務也可以保證資料庫事務的最終一致性。
可以通過訊息佇列+事務的方式實現,比如A轉賬給B,首先執行A的轉賬事務,我們在A庫中維護一個訊息表記錄轉賬訊息,然後轉賬時往這個表中寫入一條訊息。由於是同一個表,所以這兩個操作可以寫在同一個事務裡,保證了原子性。
然後我們開啟執行緒輪詢訊息表進行訊息傳送,傳送給執行B加款服務的伺服器上,對方伺服器收到訊息後,根據資訊執行對應的事務方法。
為了實現冪等性的介面,防止訊息重複,B所在的服務也要在B
庫中維護一張訊息表,記錄已經接收的訊息,避免重發。
事務訊息
實際上還可以通過支援事務訊息的訊息佇列來實現分散式事務。
這樣的訊息佇列不需要我們自己維護訊息表和傳送服務,只需要使用訊息佇列提供的事務訊息機制就可以完成事務操作。
裝配工JSP的沒落
1 最早以前的動態web應用需要使用c語言開發cgi程式,把一段段html程式碼通過c的輸出流打印出來,非常低階。
2 後來asp出現了,靜態頁面裡可以嵌入動態程式碼。隨後jsp也出現了,和asp類似,在html插入Java程式碼。
3 jsp支援使用jstl模板語言,更方便嵌入動態改變的程式碼,每次渲染時都會解析成Java語言,最後例項化成一個servlet以提供服務。
4 由於jsp經常嵌入大量Java程式碼,是在太不優雅了,於是出現了一些模板引擎,用它們來裝配html程式碼。這些模板引擎的語法和jsp類似,只不過jsp只能跑在web容器裡,而模板引擎卻可脫離web環境。
5 再後來,前端語言js興起,前端不需要讓後端來組裝html頁面了,前端自己可以提供引擎進行模板組裝,後端只需要提供資料介面和模板就可以了,前端js拿到模板和json資料後就可以自己完成裝配。模板語言和jsp這類裝配工沒有了往日的輝煌。
Java帝國之訊息佇列
1 從單機部署到多機部署,本地呼叫也變成了遠端呼叫
可以使用訊息佇列實現遠端呼叫,非同步處理訊息即可。訊息佇列會保證訊息有序,可靠,以及持久化。
2 很多訊息佇列面世,但是這些訊息佇列都沒有一個固定的實現方式,而是大家各自為政,互不相容。Java為了統一這些實現,設計了JMS。
3 一般的訊息佇列至少要分為幾個步驟,首先是繫結一個主機,該主機提供訊息服務,然後建立連線,隨後在連線上定義一個佇列,並且把訊息發到這個佇列裡。
rabbitmq對這些步驟做了一部分封裝。
1 首先通過連線工廠獲取一個連線例項。
2 在這個連線上開啟一個channel通道,類似於socketchannel。
3 在channel上宣告一個佇列queue。
4 往queue中傳送資訊
統一抽象
我們可以抽象出幾個部分,首先是連線介面connection,這個介面可以由不同MQ提供實現。
然後是Session,connection可以理解為tcp連線,session則是應用層的會話,要操作佇列,就要開啟session。
接著就是生產者,消費者,以及佇列本身。
其實這三個元件都是通過session進行建立和繫結的。
配置合程式碼分離。
connectionfactory工廠不應該直接例項化,而是通過外部注入。
為了構造不同的connection物件,我們需要注入配置檔案,考慮到不同廠商提供的connectionfactory實現不同,所以可以使用JNDI方式獲取factory工廠,jndi服務配置在web容器,暴露服務名即可。
JMS如何支援釋出訂閱模型
刪除抽象支援的是點對點的訊息模型,但事實上很多mq支援釋出訂閱的模型,一條訊息可被多個生產者消費。
為了實現這個模式,我們可以將原來的queue和topic一起,抽象為destination,而不只是一個佇列。
destination如何處理訊息可以由具體的實現類來決定,生產者和消費者可以由mq實現決定如何消費destination裡的訊息。
這就是JMS的實現方式了。
JMS實際流程
1 首先通過jndi獲取connectionfactory
2 通過jndi獲取訊息佇列的例項。
3 建立連線,然後建立session。
4 通過session建立生產者傳送訊息。
5 通過session建立消費者讀取佇列訊息
6 往隊裡發訊息和取訊息。
Java帝國之動態代理
Java執行期不允許動態修改類,所有很多動態性沒辦法實現,而像Python,php等卻可以。
由於不能動態改變類,如果我們要加入一些切面邏輯,比如事務,日誌以及許可權管理等功能,就必須修改原來的程式碼,但是顯然是很複雜和低效的。
動態代理解決
使用動態代理,雖然不能動態修改類,卻可以動態生成新類並完成載入,然後然新物件執行切面方法,再執行原來的邏輯。
實現了面向切面程式設計。
比如事務的實現,只需要在代理處理器中加入事務管理器的提交和回滾程式碼即可。
JDK動態代理要求必代理類和被代理類都要實現同一個介面。而cglib則不用。
Java註解是怎麼成功上位的
以前大家都用xml作為唯一指定配置檔案。
但是後來Java註解出現了,由於jdk允許自定義註解,並且程式可以通過反射獲取註解,於是註解的簡單易用性贏得了很多開發者的青睞,逐漸地取代了xml。
註解的使用需要定義一個@interface介面,註明target和retention。
xml配置臃腫,註解輕便快捷。
但實際上,Java註解比較分散不利於集中管理,一般用於像mvc的註解,而xml可以用在綜合的配置檔案裡,比如maven,spring配置種。
使用json可以代替xml臃腫的配置。
Java帝國之泛型
Java最早不支援泛型,但是c++支援泛型,Java借鑑這一特性,加入了偽泛型機制。
使用泛型擦除來實現,用T來表示傳入型別,比如List,然後傳入一個型別的物件後不能再傳入其他型別了。編譯時會進行泛型擦除變成object型別,使用時會強制轉成傳入型別。
1 泛型繼承
2 萬用字元
日誌系統的誕生
最早的Java列印日誌就是靠控制檯簡陋的輸出。
為了更好地管理和列印日誌
log4j
實際上可以把日誌系統分為幾個部分,一個是輸出控制器,我們叫appender,一個是格式化類,用於格式化日誌。還有一個是日誌對應的包或者類,可以作為一個日誌輸出的條件。
最後還需要一個優先順序來表示日誌的級別。
1 appender可以有檔案實現,控制檯實現,以及其他方式
2 format可以是普通格式,也可以是xml,或者是html。
3 logger作為一個類可以傳入包路徑或者類名,以便指定日誌處理範圍。
4 優先順序則會用5個常量表示,debug,info,warn,error,fatal。從低階到高階排列。
這個設計其實就是log4j的設計。
slf4j。
越來越多日誌系統出現,於是設計了一個抽象層,slf4j,提供日誌管理的api,並且可以調整底層實際的日誌系統,比如log4j,logback,jdk的logging等實現。
序列化的鹹魚翻身
1 要把Java物件儲存到硬碟中,必須進行序列化,變成二進位制資料,當然,要在網路中傳輸,實際上也是二進位制資料。
只不過應用層的協議不一定是使用二進位制進行資料序列化,還可以用xml和json.
2 使用xml的多餘資料很多,消耗的空間也比較大,而二進位制資料則更加輕量級。
但是xml可以支援多語言,按照特定協議的描述格式進行傳輸,,就可以轉化成對應語言的物件。json可以更加精簡地傳輸資料,逐漸佔領了xml的市場。
3 而Java的序列化支援Java物件的序列化和反序列化,不支援多語言。Java為了實現多語言支援,決定定義一種訊息格式,來支援不同語言的序列化與反序列化。
Java中的鎖
Java中的鎖主要就是互斥鎖。樂觀鎖可以使用cas實現。
Spring的本質
aop就是動態代理
ioc則是控制反轉,依賴注入,使用反射生成例項,通過配置檔案和註解等方式指定實現類。使用者程式碼依賴介面而不依賴與實現。
相關推薦
碼農翻身之大話程式設計篇:2我是一個Java Class
第一回 陌生警察 我出生在C盤下面一個很深層次的目錄下,也不知道是誰把我放在這裡的。我一直在睡覺,外邊的日出日落,風雨雷電和我一點關係都沒有。
《碼農翻身》之Java帝國
這位大俠,這是我的公眾號:程式設計師江湖。 分享程式設計師面試與技術的那些事。 乾貨滿滿,關注就送。 《碼農翻身》讀書筆記之Java帝國 Java帝國(Java語言發展,JVM和class,持久化和IO,JDBC與DP,JTA與分散式事務,JSP與se
碼農翻身——到底是Java好還是Python好?
語言的優劣之爭是個永恆的話題,有時候一次偶然地“擦槍走火”甚至可能會引發一場鐵桿粉絲之間的“戰爭”。 也經常有人問我:“老劉,到底是Java好還是Python好? 我應該學習哪個語言?” 我也挺為難的,只好說道: Python挺適合入門的,看起來很簡單
《碼農翻身》之浪潮之巔的Web
《碼農翻身》讀書筆記之浪潮之巔的Web 這是我的後端讀書筆記系列文章的第三篇,選取的是最近剛剛圈粉的知名博主劉欣創作的《碼農翻身》。 本文內容主要根據知名博主劉欣一作《碼農翻身》的內容總結而來,本書的內容風趣幽默,講解計算機理論原理也是十分透徹,由於書中常常
jdk源碼閱讀筆記之java集合框架(四)(LinkedList)
ray private array public 源碼閱讀 jdk源碼閱讀 oid color 解釋 關於LinkedList的分析,會從且僅從其添加(add)方法入手。 因為上一篇已經分析過ArrayList,相似的地方就不再敘述,關註點在LinkedList的特點。 屬
幹貨 | 碼農翻身提高工作效率的必備工具
ron lob 識別 書單 我們 per 高效 pytho 領域 要問闖蕩江湖的碼農最怕什麽 那麽,我鬥膽猜測一下 一定是敲代碼的 …… 速度 速度 還是速度! 速度是效率的關鍵 決定幾點回家 幾點見到心愛的妞 幾點吃雞 …… 今天,本黑就來給大家推薦一下 程序員提高效
【讀書筆記】碼農翻身 - 簡介
it行業 內容 讀書筆記 是我 筆記 然而 人生 軟件行業 積累 作為一個從業12年的老碼農來說,經歷了軟件行業十年來的滄海桑田,套用IT行業的一個術語 - “變化是永恒的”。然,追求真理,追求解決問題的金鑰匙是我們這個行業乃至人生的重要目標之一。軟件行業沒有銀彈可以解決一
【讀書筆記】碼農翻身 - 老司機的精進
成了 自己 java 進階 創新 soc 代碼 接管 node “凡事必先騎上虎背”作為來自孔子故裏的老司機,也難免沾染上儒家的中庸之道,缺少了開拓創新的精神。“凡事預則立,不預則廢”是對的,但也不必苛求盡善盡美。“不在其位,不謀其政”在我看來並不讓人奮進,畢竟 - 不想
《碼農翻身》用故事給技術加點料
這本書以故事的形式講解一些技術詞彙,總的還是比較適合理解和閱讀的,不懂的人理解更簡單,原本就理解的人就學會一種講述的方法。能通俗易懂、形像生動的把專業東西讓小白明白,是一件很不錯的事。 因為本人沒搞Java,也就把第2章大部份跳過了,,似乎作者應該是學Java的吧。 聯絡到最近希望給家裡
薦書丨好玩有趣的程式設計知識就在《碼農翻身》
點選上方“程式人生”,選擇“置頂公眾號” 第一時間關注程式猿(媛)身邊的故事 用故事給技術加點料! 好玩又有趣的程式設計知識! 全網閱讀量近1000萬次的技術故事! 優秀的技術人員應該具有廣闊的技術視野,同時擁有貫通的技術深度;不僅知道技術是什麼,而且還懂得為
碼農翻身——搞懂了這幾點,你就學會了Web程式設計
做了那麼多年Web程式設計,仔細想想, 其實本質上就那點事兒, 你抓住了幾個重點問題, 學起來一點都不難。 B/S 是從 90年代的客戶端/伺服器端發展而來, 共同點都是由一個(或一組)伺服器來服務多個客戶端。 差別在於:首先,C/S結構的客戶端可能是由不同語言編寫
碼農翻身——Redis:MySQL算老幾?
前言:上一篇《MySQL:快取算什麼東西?》裡挖了一個坑,也有很多人說沒看過癮,今天接著寫,把坑填上,不過得把視角換一下,讓Redis上臺發言。 我知道MySQL看我不順眼,不就是他的好基友Tomcat不怎麼搭理他了嗎? 這能怪我? 誰讓他那麼慢? 張大胖把我Redis安
網路簡介:網絡卡跟路由器是如何讓你上網的——《碼農翻身》閱讀筆記
聯網是這樣的,首先,你的電腦上必須要有網絡卡,否則上不了網。這章是動態撥號上網 每個網絡卡都有一個固定的MAC(Media Access Control)地址。也稱為實體地址。MAC地址由產商決定,就像身份證號碼,一般不可更改。如:11:27:F5:8A:79:54 可
碼農箴言之 效能
摘自《程式設計珠璣:續》 對於那些快速演算法,我們總是可以拿一些速度差不多但是更容易理解的演算法來替代他們。 在一些機器上,間接定址比基址定址要慢,所以請把結構體或記錄中最常用的成員放在最前面。 在一個非I/O密集型的程式中,超過一半的執行時間是花在不足4%的程式碼上的。 在優化
碼農箴言之 軟體管理
摘自《程式設計珠璣:續》 系統的結構反映出構建該系統的組織的結構。 別堅持做那些沒用的事。 [90-90法則]前90%的程式碼佔用了90%的預定開發時間,餘下的10%程式碼又花費了90%的預定開發時間。 只有不到10%的程式碼用於完成這個程式表面上的目的,餘下的都在處理輸入輸出、
碼農翻身講網路5:Web安全攻防戰與HTTPS
瀏覽器:一個家族的奮鬥 原創: 劉欣 碼農翻身 2017-12-12 我是你們每天都要使用的瀏覽器,自從90年代誕生以來,我們這個大家族變得非常的繁榮,在過去的幾十年中,我們一直兢兢業業地幫助你們人類去探索外部的網際網路世界。隨著網際網路和移動網際網路的發展,我們家族終
碼農翻身——什麼是框架?
張大胖立志走上Java之路, 聽了大神Bill的指點, 先學了Java SE, 把集合、執行緒、反射、IO、泛型、註解之類的基礎知識學了一遍, 在Bill的嚴厲督促下,寫了大量的程式碼。 然後開始學Web基礎,什麼Http, html, javascript , css
碼農翻身講作業系統2:程序,執行緒與作業系統那些事
我聽說我的祖先們生活在專用計算機裡, 一生只幫助人類做一件事情,比說微積分運算 了、人口統計了 、生成密碼、甚至通過織布機印花 ! 如果你想在這些專用“計算機”上乾點別的事兒,例如安裝個遊戲玩玩, 那是絕對不可能的, 除非你把它拆掉, 然後建一個全新的機器。 而我這些祖
《碼農翻身》讀後感
1.計算機的世界 執行緒: 執行緒執行步驟:就緒、等待、執行 多執行緒併發問題 加鎖、死鎖問題,按照資源順序申請鎖 TCP/IP 不可靠通道進行可靠性傳輸 TCP的三次握手和四次揮手 滑動視窗協議 CPU
Java匹馬行天下之Java帝國的崛起(大結局)
Java匹馬行天下之Java帝國的崛起大結局 前言: 【部落格*緣】 網路真情伴, 部落格友誼連。 笑中藏淚暖中寒。 回想那些悲喜, 苦澀也纏綿。 往事難回首, 新篇染舊言。 世間多少夢能全。 感謝相牽, 感謝遇時緣。 感謝墨中同守, 再聚是何年。 人生只如初見。 一首《部落格