mvn deploy:deploy-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs-client -Dversion=1.24 -Dpackaging=jar -Dfile=D:\\fastdfs-client-1.24.jar -Durl=http://172.16.6.214:8081/nexus/content/groups/public/ -DrepositoryId=nexus
JAR創(chuàng)建到本地
少年阿賓那些青春的歲月 |
JAR上傳到NEXUS
mvn deploy:deploy-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs-client -Dversion=1.24 -Dpackaging=jar -Dfile=D:\\fastdfs-client-1.24.jar -Durl=http://172.16.6.214:8081/nexus/content/groups/public/ -DrepositoryId=nexus JAR創(chuàng)建到本地 mvn install:install-file -DgroupId=com.home.link -DartifactId=fastdfs-client -Dversion=1.24 -Dpackaging=jar -Dfile=D:\\fastdfs-client-1.24.jar RAID 是“獨(dú)立磁盤冗余陣列”(最初為“廉價(jià)磁盤冗余陣列”)的縮略語(yǔ),1987 年由Patterson, Gibson 和Katz 在加州大學(xué)伯克利分院的一篇文章中定義。RAID 陣列技術(shù)允許將一系列磁盤分組,以實(shí)現(xiàn)提高可用性的目的,并提供為實(shí)現(xiàn)數(shù)據(jù)保護(hù)而必需的數(shù)據(jù)冗余,有時(shí)還有改善性能的作用。我們將對(duì)七個(gè)RAID 級(jí)別: 0,1,3,5,10,30 和50 作些說(shuō)明。最前面的4 個(gè)級(jí)別0,1,3,5,)已被定為工業(yè)標(biāo)準(zhǔn),10 級(jí)、30 級(jí)和50 級(jí)則反應(yīng)了ACCSTOR2000 磁盤陣列可以提供的功能。了解每個(gè)級(jí)別的特征將有助于您判斷哪個(gè)級(jí)別最適合您的需要,本文的最后一部分將提供一份指導(dǎo)方針,幫助您選擇最適合您需要的RAID 級(jí)別。RAID 級(jí)別可以通過軟件或硬件實(shí)現(xiàn)。許多但不是全部網(wǎng)絡(luò)操作系統(tǒng)支持的RAID 級(jí)別至少要達(dá)到5 級(jí),RAID10、30和50 在ACCSTOR2000 磁盤陣列控制下才能實(shí)現(xiàn)。基于軟件的RAID 需要使用主機(jī)CPU 周期和系統(tǒng)內(nèi)存,從而增加了系統(tǒng)開銷,直接影響系統(tǒng)的性能。磁盤陣列控制器把RAID 的計(jì)算和操縱工作由軟件移到了專門的硬件上,一般比軟件實(shí)現(xiàn)RAID 的系統(tǒng)性能要好。
JDK中的實(shí)現(xiàn) 在JDK中LinkedHashMap可以作為L(zhǎng)RU算法以及插入順序的實(shí)現(xiàn),LinkedHashMap繼承自HashMap,底層結(jié)合hash表和雙向鏈表,元素的插入和查詢等操作通過計(jì)算hash值找到其數(shù)組位置,在做插入或則查詢操作是,將元素插入到鏈表的表頭(當(dāng)然得先刪除鏈表中的老元素),如果容量滿了,則刪除LRU這個(gè)元素,在鏈表表尾的元素即是。 LinkedHashMap的時(shí)間復(fù)雜度和HashMap差不多,雙向鏈表的刪除和表頭插入等操作都是O(1)復(fù)雜度,故不會(huì)影響HashMap的操作性能,插入,查詢,刪除LRU元素等操作均是O(1)的時(shí)間復(fù)雜度。 LinkedHashMap不是線程安全的類,用于多線程緩存則需要花點(diǎn)心思去同步它了,JDK中有支持并發(fā)的高性能ConcurrenHashMap,沒有ConcurrenListHashMap的實(shí)現(xiàn),故要使用支持并發(fā)的高性能LRU算法還得靠自己去繼承ConcurrenHashMap或則其他方式實(shí)現(xiàn)。Google以及其它資深研發(fā)團(tuán)隊(duì)已有ConcurrenListHashMap的實(shí)現(xiàn) 當(dāng)然知道了原理,我們自己也可以來(lái)實(shí)現(xiàn)LRU算法 1.簡(jiǎn)單的計(jì)數(shù)或則LU時(shí)間標(biāo)記法 底層使用hash表,插入和訪問的時(shí)間都可以做到O(1)復(fù)雜度,容量滿了需要?jiǎng)h除LRU,則需要遍歷一遍數(shù)組,通過計(jì)數(shù)或則LU時(shí)間得到LRU,刪除之,時(shí)間復(fù)雜度O(n)。此算法簡(jiǎn)單容易實(shí)現(xiàn),適合數(shù)據(jù)量不大的需求 2.通過棧或雙向鏈表 這種算法通過維護(hù)元素的在鏈表中的順序來(lái)達(dá)到計(jì)算元素的訪問熱度,不需要額外的空間來(lái)計(jì)數(shù)或則記錄訪問時(shí)間。 插入時(shí),先檢查改元素存在此鏈表中沒有,有的刪除之,然后再將元素插入表頭。 訪問時(shí),遍歷數(shù)組查找該元素,然后將該元素移動(dòng)至表頭。 這樣一來(lái),最近被訪問的元素都在表頭,故要找出LRU則只需要?jiǎng)h除表尾元素即可。插入和訪問的時(shí)間復(fù)雜度均為O(n),如果用來(lái)作為緩存(查詢操作頻繁),相比hash表的實(shí)現(xiàn),性能相當(dāng)不好啊 3.結(jié)合HashMap和雙向鏈表 通過上面可知道HashMap可實(shí)現(xiàn)讀寫O(1)復(fù)雜度,但是找出LRU需要遍歷整個(gè)數(shù)組,而通過維護(hù)鏈表則相反,僅需要O(1)就可以找出LRU,故將兩者結(jié)合起來(lái),實(shí)現(xiàn)綜合復(fù)雜度為O(1)的LRU算法 使用數(shù)組來(lái)存放元素,插入時(shí)通過hash計(jì)算出其位置,然后改變?cè)撛卦阪湵碇械闹羔槪瑑蓚€(gè)操作的時(shí)間復(fù)雜度均為1。具體實(shí)現(xiàn)可參考JDK的LinkedHashMap http://www.360doc.com/content/14/0402/09/10504424_365635496.shtml Zookeeper的核心是原子廣播,這個(gè)機(jī)制保證了各個(gè)Server之間的同步。實(shí)現(xiàn)這個(gè)機(jī)制的協(xié)議叫做Zab協(xié)議。Zab協(xié)議有兩種模式,它們分別是恢復(fù)模式(選主)和廣播模式(同步)。當(dāng)服務(wù)啟動(dòng)或者在領(lǐng)導(dǎo)者崩潰后,Zab就進(jìn)入了恢復(fù)模式,當(dāng)領(lǐng)導(dǎo)者被選舉出來(lái),且大多數(shù)Server完成了和leader的狀態(tài)同步以后,恢復(fù)模式就結(jié)束了。狀態(tài)同步保證了leader和Server具有相同的系統(tǒng)狀態(tài)。 為了保證事務(wù)的順序一致性,zookeeper采用了遞增的事務(wù)id號(hào)(zxid)來(lái)標(biāo)識(shí)事務(wù)。所有的提議(proposal)都在被提出的時(shí)候加上了zxid。實(shí)現(xiàn)中zxid是一個(gè)64位的數(shù)字,它高32位是epoch用來(lái)標(biāo)識(shí)leader關(guān)系是否改變,每次一個(gè)leader被選出來(lái),它都會(huì)有一個(gè)新的epoch,標(biāo)識(shí)當(dāng)前屬于那個(gè)leader的統(tǒng)治時(shí)期。低32位用于遞增計(jì)數(shù)。 每個(gè)Server在工作過程中有三種狀態(tài): LOOKING:當(dāng)前Server不知道leader是誰(shuí),正在搜尋 LEADING:當(dāng)前Server即為選舉出來(lái)的leader FOLLOWING:leader已經(jīng)選舉出來(lái),當(dāng)前Server與之同步 Leader選舉流程: 當(dāng)leader崩潰或者leader失去大多數(shù)的follower,這時(shí)候zk進(jìn)入恢復(fù)模式,恢復(fù)模式需要重新選舉出一個(gè)新的leader,讓所有的Server都恢復(fù)到一個(gè)正確的狀態(tài)。Zk的選舉算法有兩種:一種是基于basic paxos實(shí)現(xiàn)的,另外一種是基于fast paxos算法實(shí)現(xiàn)的。系統(tǒng)默認(rèn)的選舉算法為fast paxos。先介紹basic paxos流程: 1 .選舉線程由當(dāng)前Server發(fā)起選舉的線程擔(dān)任,其主要功能是對(duì)投票結(jié)果進(jìn)行統(tǒng)計(jì),并選出推薦的Server; 2 .選舉線程首先向所有Server發(fā)起一次詢問(包括自己); 3 .選舉線程收到回復(fù)后,驗(yàn)證是否是自己發(fā)起的詢問(驗(yàn)證zxid是否一致),然后獲取對(duì)方的id(myid),并存儲(chǔ)到當(dāng)前詢問對(duì)象列表中,最后獲取對(duì)方提議的leader相關(guān)信息( id,zxid),并將這些信息存儲(chǔ)到當(dāng)次選舉的投票記錄表中; 4. 收到所有Server回復(fù)以后,就計(jì)算出zxid最大的那個(gè)Server,并將這個(gè)Server相關(guān)信息設(shè)置成下一次要投票的Server; 5. 線程將當(dāng)前zxid最大的Server設(shè)置為當(dāng)前Server要推薦的Leader,如果此時(shí)獲勝的Server獲得n/2 + 1的Server票數(shù), 設(shè)置當(dāng)前推薦的leader為獲勝的Server,將根據(jù)獲勝的Server相關(guān)信息設(shè)置自己的狀態(tài),否則,繼續(xù)這個(gè)過程,直到leader被選舉出來(lái)。 通過流程分析我們可以得出:要使Leader獲得多數(shù)Server的支持,則Server總數(shù)必須是奇數(shù)2n+1,且存活的Server的數(shù)目不得少于n+1. 每個(gè)Server啟動(dòng)后都會(huì)重復(fù)以上流程。在恢復(fù)模式下,如果是剛從崩潰狀態(tài)恢復(fù)的或者剛啟動(dòng)的server還會(huì)從磁盤快照中恢復(fù)數(shù)據(jù)和會(huì)話信息,zk會(huì)記錄事務(wù)日志并定期進(jìn)行快照,方便在恢復(fù)時(shí)進(jìn)行狀態(tài)恢復(fù)。 fast paxos流程是在選舉過程中,某Server首先向所有Server提議自己要成為leader,當(dāng)其它Server收到提議以后,解決epoch和zxid的沖突,并接受對(duì)方的提議,然后向?qū)Ψ桨l(fā)送接受提議完成的消息,重復(fù)這個(gè)流程,最后一定能選舉出Leader。 zookeeper數(shù)據(jù)同步過程: 選完leader以后,zk就進(jìn)入狀態(tài)同步過程。 1. leader等待server連接; 2 .Follower連接leader,將最大的zxid發(fā)送給leader; 3 .Leader根據(jù)follower的zxid確定同步點(diǎn); 4 .完成同步后通知follower 已經(jīng)成為uptodate狀態(tài); 5 .Follower收到uptodate消息后,又可以重新接受client的請(qǐng)求進(jìn)行服務(wù)了。 工作流程 Leader工作流程 Leader主要有三個(gè)功能: 1 .恢復(fù)數(shù)據(jù); 2 .維持與Learner的心跳,接收Learner請(qǐng)求并判斷Learner的請(qǐng)求消息類型; 3 .Learner的消息類型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根據(jù)不同的消息類型,進(jìn)行不同的處理。 PING消息是指Learner的心跳信息;REQUEST消息是Follower發(fā)送的提議信息,包括寫請(qǐng)求及同步請(qǐng)求;ACK消息是Follower的對(duì)提議的回復(fù),超過半數(shù)的Follower通過,則commit該提議;REVALIDATE消息是用來(lái)延長(zhǎng)SESSION有效時(shí)間。Leader的工作流程簡(jiǎn)圖如下所示,在實(shí)際實(shí)現(xiàn)中,流程要比下圖復(fù)雜得多,啟動(dòng)了三個(gè)線程來(lái)實(shí)現(xiàn)功能。 2.3.2 Follower工作流程 Follower主要有四個(gè)功能: 1. 向Leader發(fā)送請(qǐng)求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息); 2 .接收Leader消息并進(jìn)行處理; 3 .接收Client的請(qǐng)求,如果為寫請(qǐng)求,發(fā)送給Leader進(jìn)行投票; 4 .返回Client結(jié)果。 Follower的消息循環(huán)處理如下幾種來(lái)自Leader的消息: 1 .PING消息:心跳消息; 2 .PROPOSAL消息:Leader發(fā)起的提案,要求Follower投票; 3 .COMMIT消息:服務(wù)器端最新一次提案的信息; 4 .UPTODATE消息:表明同步完成; 5 .REVALIDATE消息:根據(jù)Leader的REVALIDATE結(jié)果,關(guān)閉待revalidate的session還是允許其接受消息; 6 .SYNC消息:返回SYNC結(jié)果到客戶端,這個(gè)消息最初由客戶端發(fā)起,用來(lái)強(qiáng)制得到最新的更新。 Follower的工作流程簡(jiǎn)圖如下所示,在實(shí)際實(shí)現(xiàn)中,F(xiàn)ollower是通過5個(gè)線程來(lái)實(shí)現(xiàn)功能的。 http://www.it165.net/admin/html/201405/2997.html 靜態(tài)代理 靜態(tài)代理相對(duì)來(lái)說(shuō)比較簡(jiǎn)單,無(wú)非就是聚合+多態(tài): 參考:設(shè)計(jì)模式筆記 – Proxy 代理模式 (Design Pattern) 動(dòng)態(tài)代理 我們知道,通過使用代理,可以在被代理的類的方法的前后添加一些處理方法,這樣就達(dá)到了類似AOP的效果。而JDK中提供的動(dòng)態(tài)代理,就是實(shí)現(xiàn)AOP的絕好底層技術(shù)。 JDK動(dòng)態(tài)代理 JDK動(dòng)態(tài)代理主要涉及到j(luò)ava.lang.reflect包中的兩個(gè)類:Proxy和InvocationHandler。InvocationHandler是一個(gè)接口,通過實(shí)現(xiàn)該接口定義橫切邏輯,并通過反射機(jī)制調(diào)用目標(biāo)類的代碼,動(dòng)態(tài)將橫切邏輯和業(yè)務(wù)邏輯編制在一起。 Proxy利用InvocationHandler動(dòng)態(tài)創(chuàng)建一個(gè)符合某一接口的實(shí)例,生成目標(biāo)類的代理對(duì)象。 例子:Java筆記 – 反射 動(dòng)態(tài)代理 CGLib動(dòng)態(tài)代理 還有一個(gè)叫CGLib的動(dòng)態(tài)代理,CGLib全稱為Code Generation Library,是一個(gè)強(qiáng)大的高性能,高質(zhì)量的代碼生成類庫(kù),可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口,CGLib封裝了asm,可以再運(yùn)行期動(dòng)態(tài)生成新的class。和JDK動(dòng)態(tài)代理相比較:JDK創(chuàng)建代理有一個(gè)限制,就是只能為接口創(chuàng)建代理實(shí)例,而對(duì)于沒有通過接口定義業(yè)務(wù)方法的類,則可以通過CGLib創(chuàng)建動(dòng)態(tài)代理。 CGLib采用非常底層的字節(jié)碼技術(shù),可以為一個(gè)類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,并順勢(shì)織入橫切邏輯。 JDK動(dòng)態(tài)代理和CGLib的比較 CGLib所創(chuàng)建的動(dòng)態(tài)代理對(duì)象的性能比JDK所創(chuàng)建的代理對(duì)象性能高不少,大概10倍,但CGLib在創(chuàng)建代理對(duì)象時(shí)所花費(fèi)的時(shí)間卻比JDK動(dòng)態(tài)代理多大概8倍,所以對(duì)于singleton的代理對(duì)象或者具有實(shí)例池的代理,因?yàn)闊o(wú)需頻繁的創(chuàng)建新的實(shí)例,所以比較適合CGLib動(dòng)態(tài)代理技術(shù),反之則適用于JDK動(dòng)態(tài)代理技術(shù)。另外,由于CGLib采用動(dòng)態(tài)創(chuàng)建子類的方式生成代理對(duì)象,所以不能對(duì)目標(biāo)類中的final,private等方法進(jìn)行處理。所以,大家需要根據(jù)實(shí)際的情況選擇使用什么樣的代理了。 同樣的,Spring的AOP編程中相關(guān)的ProxyFactory代理工廠內(nèi)部就是使用JDK動(dòng)態(tài)代理或CGLib動(dòng)態(tài)代理的,通過動(dòng)態(tài)代理,將增強(qiáng)(advice)應(yīng)用到目標(biāo)類中。 JDK動(dòng)態(tài)代理主要用到j(luò)ava.lang.reflect包中的兩個(gè)類:Proxy和InvocationHandler. InvocationHandler是一個(gè)接口,通過實(shí)現(xiàn)該接口定義橫切邏輯,并通過反射機(jī)制調(diào)用目標(biāo)類的代碼,動(dòng)態(tài)的將橫切邏輯和業(yè)務(wù)邏輯編織在一起。 Proxy利用InvocationHandler動(dòng)態(tài)創(chuàng)建一個(gè)符合某一接口的實(shí)例,生成目標(biāo)類的代理對(duì)象。 Cookie攻擊:
防止Cookie被抓包了之后攻擊: 就是驗(yàn)證的東西盡量多就行了,比如里面添加IP驗(yàn)證,添加一些MAC地址,添加有效期,添加 NIO通常采用Reactor模式,AIO通常采用Proactor模式。AIO簡(jiǎn)化了程序的編寫,stream的讀取和寫入都有OS來(lái)完成,不需 要像NIO那樣子遍歷Selector。Windows基于IOCP實(shí)現(xiàn)AIO,Linux只有eppoll模擬實(shí)現(xiàn)了AIO。 基于原生nio的socket通信時(shí)一種很好的解決方案,基于事件的通知模式使得多并發(fā)時(shí)不用維持高數(shù)量的線程,高并發(fā)的socket服務(wù)器的java實(shí)現(xiàn)成為現(xiàn)實(shí)。不過原生nio代碼十分復(fù)雜,無(wú)論編寫還是修改都是一件頭疼的事。“屏蔽底層的繁瑣工作,讓程序員將注意力集中于業(yè)務(wù)邏輯本身”,有需求就有生產(chǎn)力進(jìn)步, 狀態(tài)模式(state pattern)和策略模式(strategy pattern)的實(shí)現(xiàn)方法非常類似,都是利用多態(tài)把一些操作分配到一組相關(guān)的簡(jiǎn)單的類中,因此很多人認(rèn)為這兩種模式實(shí)際上是相同的。然而 •在現(xiàn)實(shí)世界中,策略(如促銷一種商品的策略)和狀態(tài)(如同一個(gè)按鈕來(lái)控制一個(gè)電梯的狀態(tài),又如手機(jī)界面中一個(gè)按鈕來(lái)控制手機(jī))是兩種完全不同的思想。當(dāng)我們對(duì)狀態(tài)和策略進(jìn)行建模時(shí),這種差異會(huì)導(dǎo)致完全不同的問題。例如,對(duì)狀態(tài)進(jìn)行建模時(shí),狀態(tài)遷移是一個(gè)核心內(nèi)容;然而,在選擇策略時(shí),遷移與此毫無(wú)關(guān)系。另外,策略模式允許一個(gè)客戶選擇或提供一種策略,而這種思想在狀態(tài)模式中完全沒有。 •一個(gè)策略是一個(gè)計(jì)劃或方案,通過執(zhí)行這個(gè)計(jì)劃或方案,我們可以在給定的輸入條件下達(dá)到一個(gè)特定的目標(biāo)。策略是一組方案,他們可以相互替換;選擇一個(gè)策略,獲得策略的輸出。策略模式用于隨不同外部環(huán)境采取不同行為的場(chǎng)合。我們可以參考微軟企業(yè)庫(kù)底層Object Builder的創(chuàng)建對(duì)象的strategy實(shí)現(xiàn)方式。 •而狀態(tài)模式不同,對(duì)一個(gè)狀態(tài)特別重要的對(duì)象,通過狀態(tài)機(jī)來(lái)建模一個(gè)對(duì)象的狀態(tài);狀態(tài)模式處理的核心問題是狀態(tài)的遷移,因?yàn)樵趯?duì)象存在很多狀態(tài)情況下,對(duì)各個(gè)business flow,各個(gè)狀態(tài)之間跳轉(zhuǎn)和遷移過程都是及其復(fù)雜的。例如一個(gè)工作流,審批一個(gè)文件,存在新建、提交、已修改、HR部門審批中、老板審批中、HR審批失敗、老板審批失敗等狀態(tài),涉及多個(gè)角色交互,涉及很多事件,這種情況下用狀態(tài)模式(狀態(tài)機(jī))來(lái)建模更加合適;把各個(gè)狀態(tài)和相應(yīng)的實(shí)現(xiàn)步驟封裝成一組簡(jiǎn)單的繼承自一個(gè)接口或抽象類的類,通過另外的一個(gè)Context來(lái)操作他們之間的自動(dòng)狀態(tài)變換,通過event來(lái)自動(dòng)實(shí)現(xiàn)各個(gè)狀態(tài)之間的跳轉(zhuǎn)。在整個(gè)生命周期中存在一個(gè)狀態(tài)的遷移曲線,這個(gè)遷移曲線對(duì)客戶是透明的。我們可以參考微軟最新的WWF 狀態(tài)機(jī)工作流實(shí)現(xiàn)思想。 •在狀態(tài)模式中,狀態(tài)的變遷是由對(duì)象的內(nèi)部條件決定,外界只需關(guān)心其接口,不必關(guān)心其狀態(tài)對(duì)象的創(chuàng)建和轉(zhuǎn)化;而策略模式里,采取何種策略由外部條件(C)決定。
Spring什么時(shí)候?qū)嵗痓ean,首先要分2種情況
第一:如果你使用BeanFactory作為Spring Bean的工廠類,則所有的bean都是在第一次使用該Bean的時(shí)候?qū)嵗?nbsp; 第二:如果你使用ApplicationContext作為Spring Bean的工廠類,則又分為以下幾種情況: (1):如果bean的scope是singleton的,并且lazy-init為false(默認(rèn)是false,所以可以不用設(shè)置),則ApplicationContext啟動(dòng)的時(shí)候就實(shí)例化該Bean,并且將實(shí)例化的Bean放在一個(gè)map結(jié)構(gòu)的緩存中,下次再使用該Bean的時(shí)候,直接從這個(gè)緩存中取 (2):如果bean的scope是singleton的,并且lazy-init為true,則該Bean的實(shí)例化是在第一次使用該Bean的時(shí)候進(jìn)行實(shí)例化 (3):如果bean的scope是prototype的,則該Bean的實(shí)例化是在第一次使用該Bean的時(shí)候進(jìn)行實(shí)例化 1、lazy init 在getBean時(shí)實(shí)例化 2、非lazy的單例bean 容器初始化時(shí)實(shí)例化 3、prototype等 getBean時(shí)實(shí)例化
<!--applicationContext.xml配置:--> <bean id="personService" class="cn.mytest.service.impl.PersonServiceBean"></bean> id是對(duì)象的名稱,class是要實(shí)例化的類,然后再通過正常的方式進(jìn)調(diào)用實(shí)例化的類即可,比如: public void instanceSpring(){ //加載spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext( new String[]{ "/conf/applicationContext.xml" }); //調(diào)用getBean方法取得被實(shí)例化的對(duì)象。 PersonServiceBean psb = (PersonServiceBean) ac.getBean("personService"); psb.save(); } 采用這種實(shí)例化方式要注意的是:要實(shí)例化的類中如果有構(gòu)造器的話,一定要有一個(gè)無(wú)參的構(gòu)造器。
二、使用靜態(tài)工廠方法實(shí)例化; 根據(jù)這個(gè)中實(shí)例化方法的名稱就可以知道要想通過這種方式進(jìn)行實(shí)例化就要具備兩個(gè)條件:(一)、要有工廠類及其工廠方法;(二)、工廠方法是靜態(tài)的。OK,知道這兩點(diǎn)就好辦了,首先創(chuàng)建工程類及其靜態(tài)方法: package cn.mytest.service.impl; /** *創(chuàng)建工廠類 * */ public class PersonServiceFactory { //創(chuàng)建靜態(tài)方法 public static PersonServiceBean createPersonServiceBean(){ //返回實(shí)例化的類的對(duì)象 return new PersonServiceBean(); } } 然后再去配置spring配置文件,配置的方法和上面有點(diǎn)不同,這里也是關(guān)鍵所在<!--applicationContext.xml配置:--> <bean id="personService1" class="cn.mytest.service.impl.PersonServiceFactory" factory-method="createPersonServiceBean"></bean> id是實(shí)例化的對(duì)象的名稱,class是工廠類,也就實(shí)現(xiàn)實(shí)例化類的靜態(tài)方法所屬的類,factory-method是實(shí)現(xiàn)實(shí)例化類的靜態(tài)方法。 然后按照正常的調(diào)用方法去調(diào)用即可: public void instanceSpring(){ //加載spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext( new String[]{ "/conf/applicationContext.xml" }); //調(diào)用getBean方法取得被實(shí)例化的對(duì)象。 PersonServiceBean psb = (PersonServiceBean) ac.getBean("personService1"); psb.save(); } 三、使用實(shí)例化工廠方法實(shí)例化。 這個(gè)方法和上面的方法不同之處在與使用該實(shí)例化方式工廠方法不需要是靜態(tài)的,但是在spring的配置文件中需要配置更多的內(nèi)容,,首先創(chuàng)建工廠類及工廠方法: package cn.mytest.service.impl; /** *創(chuàng)建工廠類 * */ public class PersonServiceFactory { //創(chuàng)建靜態(tài)方法 public PersonServiceBean createPersonServiceBean1(){ //返回實(shí)例化的類的對(duì)象 return new PersonServiceBean(); } } 然后再去配置spring配置文件,配置的方法和上面有點(diǎn)不同,這里也是關(guān)鍵所在<!--applicationContext.xml配置:--> <bean id="personServiceFactory" class="cn.mytest.service.impl.PersonServiceFactory"></bean> <bean id="personService2" factory-bean="personServiceFactory" factory-method="createPersonServiceBean1"></bean> 這里需要配置兩個(gè)bean,第一個(gè)bean使用的構(gòu)造器方法實(shí)例化工廠類,第二個(gè)bean中的id是實(shí)例化對(duì)象的名稱,factory-bean對(duì)應(yīng)的被實(shí)例化的工廠類的對(duì)象名稱,也就是第一個(gè)bean的id,factory-method是非靜態(tài)工廠方法。
然后按照正常的調(diào)用方法去調(diào)用即可: public void instanceSpring(){ //加載spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext( new String[]{ "/conf/applicationContext.xml" }); //調(diào)用getBean方法取得被實(shí)例化的對(duì)象。 PersonServiceBean psb = (PersonServiceBean) ac.getBean("personService2"); psb.save(); }
所謂原子操作,就是"不可中斷的一個(gè)或一系列操作" 。
硬件級(jí)的原子操作: 在單處理器系統(tǒng)(UniProcessor)中,能夠在單條指令中完成的操作都可以認(rèn)為是" 原子操作",因?yàn)橹袛嘀荒馨l(fā)生于指令之間。這也是某些CPU指令系統(tǒng)中引入了test_and_set、test_and_clear等指令用于臨界資源互斥的原因。 在對(duì)稱多處理器(Symmetric Multi-Processor)結(jié)構(gòu)中就不同了,由于系統(tǒng)中有多個(gè)處理器在獨(dú)立地運(yùn)行,即使能在單條指令中完成的操作也有可能受到干擾。 在x86 平臺(tái)上,CPU提供了在指令執(zhí)行期間對(duì)總線加鎖的手段。CPU芯片上有一條引線#HLOCK pin,如果匯編語(yǔ)言的程序中在一條指令前面加上前綴"LOCK",經(jīng)過匯編以后的機(jī)器代碼就使CPU在執(zhí)行這條指令的時(shí)候把#HLOCK pin的電位拉低,持續(xù)到這條指令結(jié)束時(shí)放開,從而把總線鎖住,這樣同一總線上別的CPU就暫時(shí)不能通過總線訪問內(nèi)存了,保證了這條指令在多處理器環(huán)境中的 原子性。 軟件級(jí)的原子操作: 軟件級(jí)的原子操作實(shí)現(xiàn)依賴于硬件原子操作的支持。 對(duì)于linux而言,內(nèi)核提供了兩組原子操作接口:一組是針對(duì)整數(shù)進(jìn)行操作;另一組是針對(duì)單獨(dú)的位進(jìn)行操作。 2.1. 原子整數(shù)操作 針對(duì)整數(shù)的原子操作只能對(duì)atomic_t類型的數(shù)據(jù)處理。這里沒有使用C語(yǔ)言的int類型,主要是因?yàn)椋?/span> 1) 讓原子函數(shù)只接受atomic_t類型操作數(shù),可以確保原子操作只與這種特殊類型數(shù)據(jù)一起使用 2) 使用atomic_t類型確保編譯器不對(duì)相應(yīng)的值進(jìn)行訪問優(yōu)化 3) 使用atomic_t類型可以屏蔽不同體系結(jié)構(gòu)上的數(shù)據(jù)類型的差異。盡管Linux支持的所有機(jī)器上的整型數(shù)據(jù)都是32位,但是使用atomic_t的代碼只能將該類型的數(shù)據(jù)當(dāng)作24位來(lái)使用。這個(gè)限制完全是因?yàn)樵赟PARC體系結(jié)構(gòu)上,原子操作的實(shí)現(xiàn)不同于其它體系結(jié)構(gòu):32位int類型的低8位嵌入了一個(gè)鎖,因?yàn)镾PARC體系結(jié)構(gòu)對(duì)原子操作缺乏指令級(jí)的支持,所以只能利用該鎖來(lái)避免對(duì)原子類型數(shù)據(jù)的并發(fā)訪問。 原子整數(shù)操作最常見的用途就是實(shí)現(xiàn)計(jì)數(shù)器。原子整數(shù)操作列表在中定義。原子操作通常是內(nèi)斂函數(shù),往往通過內(nèi)嵌匯編指令來(lái)實(shí)現(xiàn)。如果某個(gè)函數(shù)本來(lái)就是原子的,那么它往往會(huì)被定義成一個(gè)宏。 在編寫內(nèi)核時(shí),操作也簡(jiǎn)單: atomic_t use_cnt; atomic_set(&use_cnt, 2); atomic_add(4, &use_cnt); atomic_inc(use_cnt); 2.2. 原子性與順序性 原子性確保指令執(zhí)行期間不被打斷,要么全部執(zhí)行,要么根本不執(zhí)行。而順序性確保即使兩條或多條指令出現(xiàn)在獨(dú)立的執(zhí)行線程中,甚至獨(dú)立的處理器上,它們本該執(zhí)行的順序依然要保持。 2.3. 原子位操作 原子位操作定義在文件中。令人感到奇怪的是位操作函數(shù)是對(duì)普通的內(nèi)存地址進(jìn)行操作的。原子位操作在多數(shù)情況下是對(duì)一個(gè)字長(zhǎng)的內(nèi)存訪問,因而位號(hào)該位于0-31之間(在64位機(jī)器上是0-63之間),但是對(duì)位號(hào)的范圍沒有限制。 編寫內(nèi)核代碼,只要把指向了你希望的數(shù)據(jù)的指針給操作函數(shù),就可以進(jìn)行位操作了: unsigned long word = 0; set_bit(0, &word); /*第0位被設(shè)置*/ set_bit(1, &word); /*第1位被設(shè)置*/ clear_bit(1, &word); /*第1位被清空*/ change_bit(0, &word); /*翻轉(zhuǎn)第0位*/ 為什么關(guān)注原子操作? 1)在確認(rèn)一個(gè)操作是原子的情況下,多線程環(huán)境里面,我們可以避免僅僅為保護(hù)這個(gè)操作在外圍加上性能開銷昂貴的鎖。 2)借助于原子操作,我們可以實(shí)現(xiàn)互斥鎖。 3)借助于互斥鎖,我們可以把一些列操作變?yōu)樵硬僮鳌?/span> GNU C中x++是原子操作嗎? 答案不是。x++由3條指令完成。x++在單CPU下不是原子操作。 對(duì)應(yīng)3條匯編指令 movl x, %eax addl $1, %eax movl %eax, x 在vc2005下對(duì)應(yīng) ++x; 004232FA mov eax,dword ptr [x] 004232FD add eax,1 00423300 mov dword ptr [x],eax 仍然是3條指令。 所以++x,x++等都不是原子操作。因其步驟包括了從內(nèi)存中取x值放入寄存器,加寄存器,把值寫入內(nèi)存三個(gè)指令。 如何實(shí)現(xiàn)x++的原子性? 在單處理器上,如果執(zhí)行x++時(shí),禁止多線程調(diào)度,就可以實(shí)現(xiàn)原子。因?yàn)閱翁幚淼亩嗑€程并發(fā)是偽并發(fā)。 在多處理器上,需要借助cpu提供的Lock功能。鎖總線。讀取內(nèi)存值,修改,寫回內(nèi)存三步期間禁止別的CPU訪問總線。同時(shí)我估計(jì)使用Lock指令鎖總線的時(shí)候,OS也不會(huì)把當(dāng)前線程調(diào)度走了。要是調(diào)走了,那就麻煩了。 在多處理器系統(tǒng)中存在潛在問題的原因是: 不使用LOCK指令前綴鎖定總線的話,在一次內(nèi)存訪問周期中有可能其他處理器會(huì)產(chǎn)生異常或中斷,而在異常處理中有可能會(huì)修改尚未寫入的地址,這樣當(dāng)INC操作完成后會(huì)產(chǎn)生無(wú)效數(shù)據(jù)(覆蓋了前面的修改)。 spinlock 用于CPU同步, 它的實(shí)現(xiàn)是基于CPU鎖定數(shù)據(jù)總線的指令. 當(dāng)某個(gè)CPU鎖住數(shù)據(jù)總線后, 它讀一個(gè)內(nèi)存單元(spinlock_t)來(lái)判斷這個(gè)spinlock 是否已經(jīng)被別的CPU鎖住. 如果否, 它寫進(jìn)一個(gè)特定值, 表示鎖定成功, 然后返回. 如果是, 它會(huì)重復(fù)以上操作直到成功, 或者spin次數(shù)超過一個(gè)設(shè)定值. 鎖定數(shù)據(jù)總線的指令只能保證一個(gè)機(jī)器指令內(nèi), CPU獨(dú)占數(shù)據(jù)總線. 單CPU當(dāng)然能用spinlock, 但實(shí)現(xiàn)上無(wú)需鎖定數(shù)據(jù)總線. spinlock在鎖定的時(shí)候,如果不成功,不會(huì)睡眠,會(huì)持續(xù)的嘗試,單cpu的時(shí)候spinlock會(huì)讓其它process動(dòng)不了. |