下面的類計算并緩存了一個總和,并且在另一個類中打印這個總和
class Cache{
static {
initializeIfNecessary();
}
private static int sum;
public static int getSum(){
initializeIfNecessary();
return sum;
}
private static boolean initialized = false;
private static synchronized void initializeIfNecessary(){
if(!initialized){
for(int i=0; i < 100; i++ )
sum+=i;
initialized = true;
}
}
}
pubic class Client {
pubilc static void main(String[] args){
System.out.println(Cache.getSum());
}
}
程序是一個典型的半開循環(huán),應(yīng)該打印出1到99的整數(shù)總和,即4950,但程序運行打印的為9900,是預(yù)期值的兩倍。
程序在確保sum在使用之前就已經(jīng)初始化這個問題上,遇到了麻煩。程序結(jié)合了惰性初始化和積極初始化,還使用上了同步,以確保緩存在多線程環(huán)境下也能工作,但程序無法完成預(yù)期的工作。
程序輸出打印是控制標(biāo)志initialized 的問題。qq上一個朋友問的一本書里的問題,我也找到那本書了,是惰性初始化(static初始化)的問題,控制標(biāo)志在static完成初始化后又重新被構(gòu)造器賦值為false,初始化總和值的方法被執(zhí)行了兩次。
大概一年以前參與到一個大型信息管理軟件系統(tǒng)的維護(hù)工作中,這個系統(tǒng)是B/S結(jié)構(gòu),主要負(fù)責(zé)某省煤炭資源運銷管理,應(yīng)用在了鐵路這個渠道管理上,我們的主要的系統(tǒng)維護(hù)工作重心在鐵路管理維護(hù)上,另外還負(fù)責(zé)一些網(wǎng)站信息發(fā)布管理功能的維護(hù)。這個管理系統(tǒng)有自己的一套網(wǎng)絡(luò)體系,因為我并沒有參與其中的網(wǎng)絡(luò)體系的搭建與后期的維護(hù)工作,只是大概的了解一些:
1.網(wǎng)絡(luò)體系的結(jié)構(gòu)為樹狀拓?fù)浣Y(jié)構(gòu),主要依據(jù)該公司的組織機構(gòu)建立,該公司組織機構(gòu)分為總公司一級,分公司一級,縣級公司一級以及直接負(fù)責(zé)煤炭運銷具體的工作的公司一級。網(wǎng)絡(luò)體系以此而建,也分為四級網(wǎng)絡(luò)。
2.使用一套c/s體系的軟件,完成基礎(chǔ)數(shù)據(jù)的收集,并定時上報到縣級公司或者直屬的分公司,然后將數(shù)據(jù)匯總分析后通過這套軟件提交,統(tǒng)一儲存到總公司數(shù)據(jù)庫服務(wù)器。
3.根據(jù)該行業(yè)的業(yè)務(wù),每年全省的煤炭運量,特別是通過鐵路渠道的運量,在年初通過簽訂的全年合同決定,該年的業(yè)務(wù)也以此運量為準(zhǔn)。
這套軟件成型與2002年,在當(dāng)時的條件限制下這是一套最為有效的軟件工作體系了,但也有其缺陷:
1. 盡管基礎(chǔ)數(shù)據(jù)收集大都已經(jīng)為通過電子稱量系統(tǒng)實現(xiàn)自動數(shù)據(jù)提取,但在上報過程中,仍有可能對數(shù)據(jù)進(jìn)行篡改,軟件為此專門增設(shè)了一個子功能系統(tǒng),但使用情況不容樂觀,收效甚微。
2. 數(shù)據(jù)統(tǒng)一存儲在總公司數(shù)據(jù)庫服務(wù)器中,方便管理,在最初的設(shè)計中,數(shù)據(jù)庫沒有設(shè)計負(fù)載分流以及鏡像備份的等處理,隨著系統(tǒng)的使用,數(shù)據(jù)量的增加,數(shù)據(jù)庫負(fù)載增大,軟件反應(yīng)速度越來越慢。
這個缺陷在今年年初運量提報和每個月初的各個分公司的運量提報中尤為明顯,數(shù)據(jù)庫出現(xiàn)多次當(dāng)機情況,處理過多次,但收效不明顯,在使用高峰期需要注意數(shù)據(jù)庫的使用情況。
這個系統(tǒng)的網(wǎng)絡(luò)部分就寫這么多吧,畢竟不太熟悉,還是摻雜了軟件的非網(wǎng)絡(luò)部分,:-)。下一篇開始寫這個軟件的web架構(gòu)部分,主要是mvc框架和dao框架部分。
The Architect (dedicated non-programming technical decision maker and problem solver for business): 架構(gòu)師(專用非編程技術(shù)決策者,業(yè)務(wù)問題解決者)
|
完成該系統(tǒng)后,所完成的后期維護(hù)工作中,最大的以部分就是數(shù)據(jù)統(tǒng)計查詢分析功能的完善了。 系統(tǒng)軟件框架提供了一套報表生成系統(tǒng)來完成數(shù)據(jù)統(tǒng)計查詢的功能。這條報表生成系統(tǒng)可以生成excel和pdf兩種格式的統(tǒng)計報表。 這個系統(tǒng)使用報表的流程大致為: 1.每個功能都提供一系列的報表,在軟件中這些報表以二維字符串?dāng)?shù)組的數(shù)據(jù)格式保存,每個字符串?dāng)?shù)組對象包括該報表的唯一鍵值,報表名稱,報表條件提供頁面以及生成該報表的具體的Java類。 2.選擇需要生成的報表,系統(tǒng)將該報表的唯一鍵值傳入統(tǒng)一的報表控制類,首先是跳轉(zhuǎn)到生成該報表的條件頁面,按照功能劃分報表的主要原因就是每個功能的報表條件一致,可以使用統(tǒng)一的控制類。 3.提交條件后,統(tǒng)一的報表控制類會調(diào)用該報表的生成類,這些類需要繼承統(tǒng)一的接口,提供了一個統(tǒng)一的方法,返回數(shù)據(jù)類型為Vector集合的對象,這個Vector對象容器數(shù)據(jù)對象要求為: 兩個Vector對象,一個為表頭Vector,一個為表體Vector,這兩個Vector對象中存儲的數(shù)據(jù)為字符串?dāng)?shù)組對象。 在具體應(yīng)用中,只要將數(shù)據(jù)填充到字符串?dāng)?shù)組中,再依次放入Vector中,報表框架會生成報表。 這個框架的一個確定就是只能接受字符串?dāng)?shù)組對象,如果生成excel格式的報表,無法根據(jù)生成的報表進(jìn)行計算,必須手動的將數(shù)據(jù)調(diào)整為數(shù)字型。
|
大家喝的是啤酒,這時你入座了,給自己倒了杯可樂,這叫低配置;給自己倒了杯啤酒,這叫標(biāo)準(zhǔn)配置;給自己倒了杯茶水,這茶的顏色還跟啤酒一樣,這叫木馬;給自己倒了杯可樂,還滴了幾滴醋,不僅顏色跟啤酒一樣,不冒熱氣還有泡泡,這叫超級木馬;你同事給你到了杯白酒,這叫推薦配置。
人到齊了,酒席開始了。你現(xiàn)一個人喝了一小口,這叫單元測試;你跟旁邊的人說哥們咱們隨意,這叫交叉測試;但是他說不行,這杯要干了,這叫壓力測試;于是你說那就大家一起來吧,這叫內(nèi)部測試;這時候boss向全場舉杯,這叫公開測試。 菜過三巡,你就不跟他們客氣了,你向?qū)γ娴娜司淳疲@叫p2p;他回敬你,你又再敬他,這叫TCP;你向一桌人挨個敬酒,這叫令牌環(huán);你說只要是兄弟就干了這杯,這叫廣播。 有一個人過來向這卓敬酒,你說不行,你先過了我這關(guān),這叫防火墻。你的小弟們過來敬你酒,這叫一對多。 酒過三巡后,你也該活動活動了,你一桌一桌的走,這叫輪詢;你突然看見某一桌的漂亮mm,走了過去,這叫優(yōu)先級;你去了坐下來就不打算走了,這叫死循環(huán);你的老大舉杯邀你過去,你只好走過去,這叫激活事件。 你向一桌敬酒,他們說:“不行,不行,我們都喝白的。”于是你也喝白的。這叫本地化;你向boss敬酒,可是boss被圍起來,你只能站在外圍,這叫排隊;你終于到了內(nèi)圍,小心翼翼的向前一步,這叫訪問臨界區(qū);你拍照boss的肩膀說哥們咱們再喝已被,這叫越界。 |
一個程序員對自己的未來很迷茫,于是去問上帝:“萬能的上帝啊,請你告訴我,我的未來會怎樣?” 上帝說:“我的孩子,你去問Lippman,他現(xiàn)在領(lǐng)導(dǎo)的程序員的隊伍可能是地球上最大的。” 于是他去問Lippman,Lippman說:“程序員的未來就是駕馭程序員。” 這個程序員對這個未來不滿意,于是他又去問上帝:“萬能的上帝呀,請你告訴我,我的未來會怎樣?” 上帝說:我的孩子,你去問Gates,他現(xiàn)在所擁有的財產(chǎn)可能是地球上最多的。” 于是他去問Gates,Gates說:“程序員的未來就是榨取程序員。” 這個程序員對這個未來不滿意,于是他又去問上帝:“萬能的上帝啊,請你告訴我,我的未來會怎樣?” 上帝說:“我的孩子,你去問侯捷,他寫的計算機書的讀者可能是地球上最多的。” 于是他去問侯捷。 侯捷說:“程序員的未來就是誘惑程序員。” 這個程序員對這個未來不滿意,于是又去問上帝:“萬能的上帝啊,請你告訴我,我的未來會怎樣?” 上帝搖搖頭:“唉,我的孩子,你還是別當(dāng)程序員了。” |
該系統(tǒng)軟件框架對sql操作進(jìn)行了封裝,并提供了一批API幫助客戶程序員更為簡便的進(jìn)行數(shù)據(jù)庫操作。這些api包括:
這個數(shù)據(jù)庫框架還提供了一些方便編寫代碼的操作,例如拼裝sql語句,提供了一個這樣的方法:MakeUp類。代碼如下: java 代碼
這個makeUp方法會將sql語句拼裝好,@表示數(shù)字占位,#表示字符占位。 這個系統(tǒng)的數(shù)據(jù)庫操作管理大致就是這樣了,比較簡單,總的來說就是對dbconncetion 操作進(jìn)行了重新封裝,方便客戶程序員的使用。
|
維護(hù)的這個軟件系統(tǒng)使用了一個比較復(fù)雜的系統(tǒng)權(quán)限管理系統(tǒng),原本的設(shè)計是將用戶對軟件的使用權(quán)限控制到以最末級的菜單,并根據(jù)公司組織機構(gòu)的設(shè)計,上級組織單位可以將自身所獲得的權(quán)限繼續(xù)授權(quán)到自己的下級公司。
為了授權(quán)權(quán)限的操作簡單話,不然每次都從幾百個菜單選項中選擇給該用戶授權(quán)的菜單權(quán)限,恐怕這個權(quán)限系統(tǒng)管理員就要崩潰了。:-),權(quán)限管理系統(tǒng)將權(quán)限分為了權(quán)限組,權(quán)限域,基本權(quán)限管理。 權(quán)限組和權(quán)限域的區(qū)別我至今沒有太分的清楚,郁悶中····在不多的使用當(dāng)中(主要是設(shè)置測試用戶的權(quán)限)感覺上這兩種權(quán)限范圍設(shè)置是評級的,沒有誰是誰的上級的關(guān)系,不清楚當(dāng)初為什么設(shè)置成這樣,我用的主要是權(quán)限域的設(shè)置。 給用戶授權(quán)下權(quán)限,前提是已經(jīng)有相應(yīng)的權(quán)限域設(shè)置。 1.權(quán)限域設(shè)置:權(quán)限域需要相應(yīng)的設(shè)置編碼,并選擇該權(quán)限域包括的菜單權(quán)限。 2.在設(shè)置好權(quán)限域后,就可以直接將該權(quán)限域授權(quán)到系統(tǒng)用戶。 權(quán)限管理使用了數(shù)據(jù)庫信息管理,現(xiàn)在使用起來比較笨拙,不過由于最初的設(shè)置過于復(fù)雜,如果使用現(xiàn)在比較統(tǒng)一的xml文件配置,可能使用起來也不是很方便。 每個菜單權(quán)限項都有一個自身的權(quán)限編碼,該系統(tǒng)的菜單全部分為三級,編碼規(guī)范為:一級菜單編碼_二級菜單編碼_三級菜單編碼。這樣,在授權(quán)權(quán)限的時候可以直接將一級菜單授權(quán),用戶相應(yīng)的也獲得該一級菜單下所有功能的使用權(quán)。 用戶登錄成功后系統(tǒng)會將該用戶的合法權(quán)限值壓到一個集合中,放到sessin對象里。 權(quán)限的控制在系統(tǒng)的頁面和后臺控制類都有實現(xiàn)。頁面使用了上一篇提到的頁面邏輯標(biāo)簽實現(xiàn)控制,在顯示該頁面之前,控制類使用了個系統(tǒng)框架提供的公共權(quán)限控制類將該用戶的權(quán)限值壓到頁面值中。 在調(diào)用該功能之前,控制類現(xiàn)會判斷該用戶的權(quán)限,有一個通用類,將該功能的權(quán)限和當(dāng)前的用戶對象作為參數(shù)傳入,該類會判斷在用戶的權(quán)限集合中是否包括該權(quán)限,以決定是否繼續(xù)執(zhí)行該功能流程。 這個系統(tǒng)的權(quán)限管理部分就是這么多了,下一篇講講這個系統(tǒng)的數(shù)據(jù)庫管理部分。維護(hù)的這個軟件系統(tǒng)使用了一個比較復(fù)雜的系統(tǒng)權(quán)限管理系統(tǒng),原本的設(shè)計是將用戶對軟件的使用權(quán)限控制到以最末級的菜單,并根據(jù)公司組織機構(gòu)的設(shè)計,上級組織單位可以將自身所獲得的權(quán)限繼續(xù)授權(quán)到自己的下級公司。 為了授權(quán)權(quán)限的操作簡單話,不然每次都從幾百個菜單選項中選擇給該用戶授權(quán)的菜單權(quán)限,恐怕這個權(quán)限系統(tǒng)管理員就要崩潰了。:-),權(quán)限管理系統(tǒng)將權(quán)限分為了權(quán)限組,權(quán)限域,基本權(quán)限管理。 權(quán)限組和權(quán)限域的區(qū)別我至今沒有太分的清楚,郁悶中····在不多的使用當(dāng)中(主要是設(shè)置測試用戶的權(quán)限)感覺上這兩種權(quán)限范圍設(shè)置是評級的,沒有誰是誰的上級的關(guān)系,不清楚當(dāng)初為什么設(shè)置成這樣,我用的主要是權(quán)限域的設(shè)置。 給用戶授權(quán)下權(quán)限,前提是已經(jīng)有相應(yīng)的權(quán)限域設(shè)置。 1.權(quán)限域設(shè)置:權(quán)限域需要相應(yīng)的設(shè)置編碼,并選擇該權(quán)限域包括的菜單權(quán)限。 2.在設(shè)置好權(quán)限域后,就可以直接將該權(quán)限域授權(quán)到系統(tǒng)用戶。 權(quán)限管理使用了數(shù)據(jù)庫信息管理,現(xiàn)在使用起來比較笨拙,不過由于最初的設(shè)置過于復(fù)雜,如果使用現(xiàn)在比較統(tǒng)一的xml文件配置,可能使用起來也不是很方便。 每個菜單權(quán)限項都有一個自身的權(quán)限編碼,該系統(tǒng)的菜單全部分為三級,編碼規(guī)范為:一級菜單編碼_二級菜單編碼_三級菜單編碼。這樣,在授權(quán)權(quán)限的時候可以直接將一級菜單授權(quán),用戶相應(yīng)的也獲得該一級菜單下所有功能的使用權(quán)。 用戶登錄成功后系統(tǒng)會將該用戶的合法權(quán)限值壓到一個集合中,放到sessin對象里。 權(quán)限的控制在系統(tǒng)的頁面和后臺控制類都有實現(xiàn)。頁面使用了上一篇提到的頁面邏輯標(biāo)簽實現(xiàn)控制,在顯示該頁面之前,控制類使用了個系統(tǒng)框架提供的公共權(quán)限控制類將該用戶的權(quán)限值壓到頁面值中。 在調(diào)用該功能之前,控制類現(xiàn)會判斷該用戶的權(quán)限,有一個通用類,將該功能的權(quán)限和當(dāng)前的用戶對象作為參數(shù)傳入,該類會判斷在用戶的權(quán)限集合中是否包括該權(quán)限,以決定是否繼續(xù)執(zhí)行該功能流程。 這個系統(tǒng)的權(quán)限管理部分就是這么多了,下一篇講講這個系統(tǒng)的數(shù)據(jù)庫管理部分。 |
這個軟件架構(gòu)使用的mvc架構(gòu)包括使用自身一套頁面邏輯,標(biāo)簽類型比較簡單,包括邏輯判斷標(biāo)簽、頁面賦值標(biāo)簽和循環(huán)list對象取值標(biāo)簽。
在執(zhí)行完頁面請求返回的頁面沒有規(guī)定,可以是jsp,也可以是html頁面,使用上一篇提到的Common對象跳轉(zhuǎn)頁面,方法為:common.showPage("page")方法,因為沒有該框架的這部分源代碼,只能大概推測,這個方法是讀入頁面,并將執(zhí)行頁面含有的邏輯標(biāo)簽和賦值,一個方法可以多次使用該方法,最后的執(zhí)行結(jié)果是多個頁面順次顯示,比如: ![]() ![]() ![]() ![]() ![]() page1的頁面代碼: ![]() ![]() ![]() ![]() ![]()
page2的頁面代碼:
![]() ![]() ![]() ![]() ![]()
最后顯示的頁面代碼:
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 頁面的邏輯標(biāo)簽很簡單:<if><else><endif>,完成簡單的頁面邏輯判斷 在頁面最終生成之前執(zhí)行的代碼,common的showpage方法會將標(biāo)簽作為java代碼執(zhí)行。 頁面賦值標(biāo)簽寫法很簡單:($value$),value為要獲取的參數(shù)值,使用$符號區(qū)隔,可以和邏輯標(biāo)簽混合使用: <if ($value$)==1>1<else>2<endif> 寫法有些類似現(xiàn)在流行的mvc開源框架。 另一個常用的循環(huán)標(biāo)簽:<loop ($list$) ></loop> list為循環(huán)的集合對象。也可以同時循環(huán)多個list集合對象,但前提是多個對象的集合大小相同,不然就會出現(xiàn)數(shù)組溢出的錯誤。 該mvc框架配合了一套js腳本庫一同使用,因此像一些常用的腳本方法就和mvc框架的一些特點結(jié)合起來使用,js代碼編寫量減少。 表單提交參數(shù)驗證有一套統(tǒng)一的方法,現(xiàn)在應(yīng)該應(yīng)用的很普遍了。在表單對象標(biāo)簽里增加一些屬性,最后提交表單是調(diào)用統(tǒng)一表單驗證方法,該方法會讀取該對象的屬性,判斷該對象值是否符合要求,包括判斷復(fù)選框?qū)ο笫欠裼羞x擇對象,例如在刪除列表中的多個對象使用。 在常用的查詢列表和該列表的某個具體對象時,腳本庫提供了統(tǒng)一的方法: 1、常用的翻頁方法,首頁,尾頁,上一頁,下一頁,跳轉(zhuǎn)到某一頁的方法,只需要使用腳本庫中統(tǒng)一的方法,傳入表單名稱參數(shù),class名稱,method名稱,跳轉(zhuǎn)到某一頁需要再傳入頁面參數(shù)即可,不需在編寫js代碼。 2. 查看某一條具體記錄,方法類似于翻頁方法,同樣傳入表單名稱參數(shù),class名稱,method名稱表單名稱參數(shù),class名稱,method名稱,和該條記錄的主鍵值。 今天寫到這里,下一篇寫寫這個系統(tǒng)的權(quán)限系統(tǒng)。 |
今天總結(jié)一下這個系統(tǒng)軟件使用的系統(tǒng)架構(gòu)。 這個軟件使用的mvc框架有點類似于struts,我是在2005年開始接觸java的,在維護(hù)這個系統(tǒng)軟件之前使用的mvc框架包括struts和webwork兩種,相比較之下,與strtus更為類似,或許也是因為strus中控制類部分也是直接操作request吧。 這個mvc框架自身的特點大致有這么幾個: 1.這個mvc框架沒有使用配置文件,在webconfig文件中配置有一個總控的servlet,負(fù)責(zé)接受頁面提交的請求,進(jìn)行轉(zhuǎn)發(fā)。 頁面提交請求方式是直接請求這個總控servlet,在提交請求到這個servlet的同時,提交兩個固定的參數(shù),分別是class和method參數(shù),通知servlet將請求轉(zhuǎn)到相應(yīng)的類,并調(diào)用參數(shù)中的方法。 2.總控servlet調(diào)用的類為普通的java類,沒有特殊的要求,比如struts中要繼承action父類,方法寫法有嚴(yán)格的要求,為靜態(tài)方法,不允許有返回參數(shù),接受的參數(shù)也固定,如下: public static void expMethod(HttpServletRequest req, 因為沒有使用配置文件,方法調(diào)用結(jié)束后返回到哪個頁面,在該方法中直接賦值該頁面的具體路徑。這樣修改起來有點復(fù)雜,需要重新編譯類,并且在調(diào)試的時候,如果需要找到該請求調(diào)用的頁面的具體路徑,必須找到這個類和方法,不如使用配置文件一目了然。 3.獲取頁面上的參數(shù),這個框架提供兩種不同的選擇。 框架提供一個Common的對象,該對象封裝了對request的部分操作,提供了一個RequestHash對象,該對象為一個Vector集合,頁面表單提交的數(shù)據(jù)已經(jīng)封裝到該集合中,參數(shù)獲取方式為,創(chuàng)建一個字符串?dāng)?shù)組,將需要獲取的參數(shù)名稱賦值到該數(shù)組中,Common的toData方法返回與字符串?dāng)?shù)組相對應(yīng)的參數(shù)值,如下 Common common = new Common(req,res);//req request對象,res為response對象 String[] keys = {"param1","param2"}; 此時values數(shù)組中,values【0】中的值為param1表單值,相應(yīng)的為param2的表單值。 如果需要獲取一個數(shù)組值,request的操作是getParamValues方法,例如表單中的復(fù)選框值,RequestHash對象提供了類似于request的這個操作。 reh.getParameterValues("params"); 4.為顯示頁面賦值也使用了Common對象。 a、 賦值簡單的字符串對象:common.addString("showParam", param); 第一個參數(shù)為頁面獲取該參數(shù)值使用的名稱,第二個為該對象名稱。 b、一次性賦值多個字符串對象:common.addArray(keys, values); 相對應(yīng)的,keys為頁面獲取參數(shù)值的名稱,values為參數(shù)的值。 c、賦值一個復(fù)雜的對象,例如自定義對象或者一個List對象: common.addObject("voname", vo); 用法一致。 該框架提供一套通用的js腳本庫和一些統(tǒng)一的賦值規(guī)則,例如登錄用戶對象名稱,子系統(tǒng)名稱和提示名稱,因此common對象賦值也提供了一些特殊的方法,只接受參數(shù)的值,參數(shù)名稱為已定義名稱,因此在為頁面賦值也要注意不要與系統(tǒng)框架已定義對象名稱沖突。 今天寫到這里,下一篇寫寫這個mvc框架的頁面邏輯,標(biāo)簽還有這個腳本庫的內(nèi)容吧。 |