當前位置:首頁 » 編程語言 » java池化

java池化

發布時間: 2022-08-19 14:55:12

java問題:Cannot create PoolableConnectionFactory

不能建立池化連接工廠

你檢查你的數據源配置,例如資料庫地址、url、用戶名、密碼
如果這些都對,那麼再檢查網路連接,包括你這邊和資料庫伺服器那邊的。

這個錯誤總之就是不能連接資料庫產生的

❷ 【Java基礎】線程池的原理是什麼

什麼是線程池?

總歸為:池化技術 ---》資料庫連接池 緩存架構 緩存池 線程池 內存池,連接池,這種思想演變成緩存架構技術---> JDK設計思想有千絲萬縷的聯系

首先我們從最核心的ThreadPoolExecutor類中的方法講起,然後再講述它的實現原理,接著給出了它的使用示例,最後討論了一下如何合理配置線程池的大小。

Java 中的 ThreadPoolExecutor 類

java.uitl.concurrent.ThreadPoolExecutor 類是線程池中最核心的一個類,因此如果要透徹地了解Java 中的線程池,必須先了解這個類。下面我們來看一下 ThreadPoolExecutor 類的具體實現源碼

在 ThreadPoolExecutor 類中提供了四個構造方法:

❸ java軟體開發的架構設計

軟體架構作為一個概念,體現在技術和業務兩個方面。
從技術角度來說:軟體架構隨著技術的革新不斷地更新其內容,軟體架構建立於當前技術和一些基本原則的基礎之上。
先說一些基本原則:
分層原則:分層是為了降低軟體深度復雜性而使用的關鍵思想,就像社會有了階級一樣,軟體有了層次結構。
模塊化原則:模塊化是化解軟體廣度復雜的必然手段,模塊化的目的就是讓軟體分工。
介面實現分離原則隨著軟體模塊化的不斷深入改進,面向介面編程而不是面向實現編程可以讓復雜度日趨增高的軟體降低模塊之間的耦合度,從而讓各模塊更輕松改進。從這個原則出發,軟體也從微觀進行了細致的規范化。
還有兩個比較小但很重要的原則:
細節隱藏原則很顯然把復雜問題簡化,把難看的細節隱去,能讓軟體結構更清晰。其實這個原則使用很普遍,java/c++語言中的封裝原則以及設計模式中的Facade(外觀)模式就很能體現這個原則的精神。
依賴倒置原則隨著軟體結構的進一步發展,層與層之間、模塊與模塊之間的依賴逐漸加深,而層、模塊的動態可插拔要求不端增大。依賴倒置原則可看視為介面實現分離原則的深化,根據此原則的精神,軟體進入了工具時代。這個原則有點類似於知名的好萊塢法則:Don't call us, we'll call you。
以上這些原則奠定了我們的軟體架構的價值指標。但軟體架構畢竟是建立在當前技術之上的。而每一代技術都有架構模式。過去的不再說了,讓我們就來看一下當前流行的技術,以及當前我們能採用的架構。
因為面向對象是當前最流行開發技術,且設計模式的大量使用使面向對象的走向成熟,而資料庫是當前最有效的存儲結構、web界面是當前最流行的用戶介面,所以當前最典型的三層次架構就架構在以上幾項技術的基礎之上,用資料庫作存儲層、用面向對象來實現業務層、用web來作為用戶介面層。我們從三層次架構談起:
因為面向對象技術和資料庫技術不適配,所以在標准三層次架構的基礎上,我們增加了數據持久層,來管理O-R雙向映射,但目前一直沒有最理想的實現技術。cmp和entity bean技術因為其實現復雜,功能前景有限,已接近被淘汰的邊緣。JDO及hibernate作為o-r映射的後期之秀,尤其是hibernate,功能相當完備。推薦作為持久層的首選
在業務層,因為當前業務日趨負載,且變動頻繁,所以我們必須有足夠敏捷的技術來保證我們的適應變化的能力,在標准j2ee系統中session bean負責業務處理,且有不錯的性能表現,但採用ejb系統對業務架構模式改變太大,且其復雜而昂貴,業務代碼移植性差。而spring 作為一個bean配置的輕量級架構,漂亮的IOC模式實現,對業務架構影響小,所以推薦作為中間層業務框架。
在用戶結構層,雖然servlet/jsp/jstl/javaBean 能夠實現MVC架構,但終究過於粗糙。struts對MVC架構的實現就比較完美,Taperstry也極好地實現MVC架構,且採用基於事件的方式,非常誘人,惜其不夠成熟,我們仍舊推薦struts作為用戶介面層基礎架構。
因為業務層是三層次架構中最有決定意義的,所以讓我們回到業務層細致地分析一下,在復雜的業務我們常常需要以下基礎服務的一種或幾種:事務一致 性服務acid(tool:jta/jts)、並發加鎖服務concurrent&&lock、池化管理服務cache、訪問控制服務(tool:jaas)、流程式控制制服務workflow、動態實現服務IOC,串列化消息服務(tool:jms)、負載平衡服務blance等。如果我們不採用重量級應用伺服器(如weblogic,websphere,jboss等)及重量級組件(EJB),我們必須自己實現其中一些服務。雖然我們大 多情況下,不需要所有這些服務,但實現起來卻非易事。幸運的是我們有大量的開源實現代碼,但採用開源代碼卻常常是件不輕松的事。
隨著xml作為結構化信息傳輸和存儲地位日漸重要,一些xml文檔操作工具(DOM,Digester,SAX等)的使用愈發重要,而隨著 xml schema的java binding工具(jaxb,xmlbean等)工具的成熟,採用xml schema來設計xml文檔格式,然後採用java binding來生成java bean 會成為主要編程模式,而這又進一步使數據中心向xml轉移,使在中小數據量上,愈發傾向於以xquery為查詢語言的xml資料庫。現還有一個趨勢, microsoft,ibm等紛紛大量開發中間軟體如(microsoft office之infopath),可以直接從xml schema 生成錄入頁面等非常實用的功能。還有web service 的廣泛應用,都將對軟體的架構有非常重大的影響。至於面向服務架構(SOA)前景如何,三層次架構什麼時候走入歷史,現還很難定論。
aop的發展也會對軟體架構有很深的影響,但在面向對象架構里,無論aspectJ還是jboss-aop抑是aspectWerks、 nanning都有其自身的嚴重問題:維護性很差,所以說它將很難走遠。也許作為一個很好的思想,它將在web service里大展身手。
rdf,owl作為w3c語義模型的標志性的語言,也很難想像能在當前業務架構發揮太大影響。但如果真如它所聲稱那樣,廣泛地改變著信息的結構。那麼對軟體架構也會有深遠影響。

❹ .net和java的區別及各自的優缺點

平台之爭 Java與.NET誰更有前途
2009-2-18 網友評論 1 條 點擊進入論壇
為什麼會有Java,為什麼會有.NET

有人說,Java是為了跨Windows和UNIX而產生的。是這樣嗎?Sun有自己的操作系統solaris,並且打的是高端市場,而Java發展早期階段,Windows還主要定位在中小型企業,並沒有打算與Sun一爭高端客戶。

而且Sun的用戶大部分都是大型企業級,而Windows定位在家庭消費用戶,由於Windows已經成為桌面OS的事實標准,Sun根本無意搶奪 Windows的地盤,而且Sun有自己的操作系統,擴大自己產品銷售才是第一。

但是UNIX一直是個混亂的世界,各種UNIX版本在並存,你為這種 UNIX開發的應用,卻很難在另一種UNIX上跑通.應用的阻塞影響了UNIX市場需求的擴大,就象沒有SQL Server,沒有OFFICE,沒有Windows 游戲,和Windows上的開發工具,就算你的操作系統做的再漂亮再容易我們也會扔掉Windows.為什麼?因為沒用,我買回來一個大鐵傢伙,我什麼也做不了.Sun就出於這種考慮,所以才有VM的想法,否則誰傻了,做個又慢又麻煩的VM.所以說Java的產生,只是為了跨UNIX平台.當然能跨 Windows,吃定Windows,那豈不是更好,呵呵呵,Sun為自己的妙招而沒事偷著樂.

那為什麼會有.NET呢?可是Windows就一個呀,它也要跨平台?而且微軟已經把CLI提交給標准委員會,看來是真要跨了?真的嗎?

從外表來看,Windows確實是一個.但是從技術角度來看,Windows3,Windows95,Windows2000是截然不同的三種架構.在中國,大家對新技術的追求比較熱衷,所以說一個企業中這三種操作系統並存互連的可能性不怎麼大.但是老外是精打細算,不見兔子不撒鷹,所以你在國外企業運行很老的系統也不要見怪.微軟為了同時維護這幾種操作系統也是煞費苦心,而且由於技術是各個時期形成的,有的技術由於歷史發展原因有明顯的缺陷,也無能為力修改了,而且為了功能更強大,API海洋,DLL黑洞,ACTIVEX,OLE,COM,DCOM,COM+,各種技術交叉,唉,其中苦誰了解?所以跨WINDWOS平台是微軟製造.NET的一個原因,這樣給你一個抽象的統一的平台後把你擺平後,他再著手修改他的底層,省得一天人們叫著 Windows不安全,Windows不穩定.當然從J2EE的火熱場面來看,拉去了很大一批Windows平台上的C++程序員.失去了應用開發的源頭,那還有什麼發展?如何拉回這批程序員讓他們繼續為Windows開發當然也是.NET的原因之一,這就是為什麼.NET從架構到開發語言都與 Java極其相似的原因,就是吸引你平滑的再回到微軟的世界中,如果跨度大了,程序員就有了遲疑.唉,如果沒有Java,如今的C#也不會是如今這樣,原本它會更好,我想ANDERS一定心中很郁悶,但是商業是不以個人意志為轉移的.而且現在已經不是桌面為王的時代了,現在是互連網的時代,Java是第一個有強大開發WEB應用的完整體系,而當時微軟的技術還是七拼八湊,只是互連網一下到來微軟剛醒過神來倉促應戰的結果,當然無法與J2EE媲美.想在互連網時代也分一杯羹,必須也有一個完整的體系,於是.NET就產生了.

我們已經有了Web Service,我們還需要.NET嗎?

其實技術發展到如今的應用集成時代,用戶的需求就是把現在各種平台上的應用集成起來.集成的方法有很多種,當然跨平台也是一種.不過最省力的還算是WEB SERVICE.因為現在已經是組件應用的天下.各種COM,EJB,CORBA成為快速組裝企業應用的主流技術.組件是位於操作系統,資料庫,網路之上的技術,站在組件的層面上,下面用什麼技術已經無所謂了,因為已經被組件屏蔽了.如果我們能把我們的組件互連起來,不也可以集成嗎?應該怎麼做?這幾項技術都分屬於不同公司,想聯合真不大容易.這時就要找到每個體系公共的東西,用公共的東西把他們連在一起不就行了.找呀找,終於發現,是TCP/IP.隨即幾大公司都發現了突破口,需要快速佔領先機.由於Sun一直在Java發展的問題上給了IBM很大的阻塞,所以IBM寧願先和微軟聯合做,如果微軟有什麼不軌之心,就放出Sun,讓他們互相咬,然後在適當的時機出來裝出老大的樣子擺平他們,給他們倆制定一個適合自己發展的競爭協議.

我們已經可以互連了,我們干嗎要.NET.我們的問題已經解決了,我干嗎花錢再投資呢?經濟本來已經很不景氣了.

但是,微軟看來已經決定不在現有基礎上增強ASP和COM+了,現在是互連時代,也是組件時代,兩大要命的地方我都不升級了,你自己看著辦,我可沒逼著你買.

.NET和Java在中國哪個更有前途?

這個問題好象已經不用再爭了.中國90%的用戶是Windows用戶,保護現有投資,使用很習慣很易用不用重新學習,我又不用跨平台,我干嗎要換Java 呢.過去是微軟沒有提供很強大的WEB開發解決方案,現在提供了,我干嗎要用Java.而且. Net比Java出的遲,肯定會吸收Java的優點,彌補Java的缺點.而且微軟的VM肯定和Windows結合的很好,性能不用擔心.我干嗎用 Java?而且微軟顯然把寶已經壓到了.NET上,你難道還要在.NET的VM上再加一層Java的VM?

.NET有什麼新的亮點?

當然是ASP,ADO和COM+,還有清晰的架構,並且由於統一的類庫,我們為WEB,GUI,MOBILE而開發的應用會很容易的轉來轉去,不象過去開發,各需要學習不同的知識.ASP終於結束了網頁義大利面條式的程序,面向對象和支持多種語言,使構築強大復雜的WEB應用提供了比JSP更兇猛的功能,讓人不得不愛.ADO.NET也拋棄了過去的數據集一Scroll就連資料庫進行提交的糟糕速度,代而取之的是多條修改可以一次性提交上去.這樣性能會提高很多.COM+呢?COM+1.5的特性大家在WINXP上也看見了,比1.0強了很多,未來還不用注冊, COPY完就能用,多舒服.至於安全嘛,穩定嘛,這話不敢講.因為盜亦有道,Java也同樣如此,無法說誰比誰好.

.NET真的會跨平台嗎?

微軟的命根子是操作系統,微軟此次出.NET也是為了打入高端市場.怎麼打入?微軟第一已經在用C#收買 Java程序員了,並且做Java和C#的映射工具,先斷了Java應用的前途,後面用CLI提交給標准委員會,讓別人開發UNIX上的平台,微軟不在正面和UNIX陣營沖突,以免犯眾怒.當UNIX和Windows的CLI都有了時候,基於CLI的應用可就兩個系統都能用了,這會幫助微軟銷售多少其他產品呀.這不,微軟在支持著好幾個Open Source社團在開發UNIX的CLI.跨平台的事微軟不會輕易乾的,否則微軟的命根子怎麼辦?

.NET真的支持多種語言嗎?

開發更多的基於.NET的應用,讓.NET快速成長起來.第二.NET是一次比較大的革新,廣大的各類程序員能否跟的上也是個問題.多語言的支持當然會,但是不會支持的很好,否則微軟大力做C#干嗎呀,如果別的語言和C#一樣好,那微軟還混什麼混呀.最糟糕了,也要其他語言的技術比C#慢半拍.不過先走也未必領先,就象DELPHI就後來居上,這么大的市場,微軟是不可能通吃的.

我們需要轉到.NET上嗎?

你可以不轉.就看你需要不需要INTERNET了.我想在未來,沒有企業會說INTERNET對我沒有一點作用.

現有應用能否平滑過渡呢?

在這個問題上可以看一下微軟的歷史.微軟在做完WINNT4的時候其實已經在策劃現在的WIN2000,但是為什麼在WIN95後有WIN98, WINME,WINXP,不是他當時做不了那樣的技術,而是必須引導著客戶一步步走,要追隨客戶,走的太快,就會丟失客戶.在這個重大的轉折點,微軟也會如此.而且在現在的Windows.NET上,你運行現在的程序一樣沒問題,速度依舊,操作方式也依舊,因為他使用了兩種手段來區別對待這兩種應用程序.

什麼時候轉?

如果你需要搶占市場先機,現在轉正好,因為能支持ASP.NET,ADO.NET開發的VSS.NET已經推出快一年了,就是有能力欠缺的問題,第二版的出來也不會太晚了.不過話在前頭,確實在實際的開發中,Vss.NET確實有些做不了的事情,不要看他好象什麼都有,這就跟微軟當年宣布COM有池化的功能一樣,僅有一個外殼.這是微軟的策略,跟不跟著走,你自己看.穩健型的公司建議在第二版出來後應用,因為微軟的產品一向在第三版才會好用.

作為開發商,跟隨.NET的難點是什麼?

難點難就在,過去我們的開發方式,拖一些控制項,連個資料庫,更新或SELECT一些數據.再深一些就是消息,或者是一些不常用的API.記住:.NET是微軟進攻高端市場的第一步,現在的微軟不是我們過去熟悉的微軟,Vss.NET的一推出,就是強烈給人一種這樣的感受:從建模到開發到測試到發布,全套企業級的工具都無縫相接,而且處處體現著OO和設計模式,在宣傳中也頻繁提到,昭示著這個工具是為大型應用開發而定製的.所以寶刀也需有能力的人才能拿的動,否則只能砸了自己的腳.對於現在的Java開發工具也是如此,好象全世界一下都沒有了小型企業一樣.我們是否具備了優秀的設計師,建模師,OOP的程序員,我們是否有一整套流暢的開發流程來支持全程建模,我們都需要深思.在微軟的.NET的各種培訓上,培訓師也是反復強調分析設計,大型項目管理,自動化工具的支持,你做好准備了嗎?

Sun在微軟拆分問題上輸了嗎?

微軟的案子打了這么多年,居然庭外和解.Sun確實挺郁悶.不過Sun並沒有輸.為什麼這么說呢?依毛主席的話說就是:敵進我退,敵疲我擾.確實微軟在. NET的發展上受了很多牽絆,否則也不會到如今才推出來個框架.在矽谷,時間就是機會,時間就是金錢,誰前進的快誰就能佔先機,顯然Sun並不是最痛苦的一個.

Java的未來

依Windows的用戶量和微軟進攻高端企業應用的決只是呆板的圖形,不能全方位的表現網路的傳輸技術,使應用進步更加依賴硬體而不是軟體,微軟亞洲研究院為什麼在做哪些研究,就是因為他們不斷在思考未來是什麼,所以每一次技術的浪潮他們總在浪頭.當然未來還會有所改變,但是他們會及時調整他們的戰略,但大方向不會錯到哪去!

當技術不再是阻礙應用發展的主要因素,比如寬頻的來臨,這時候你想過沒有,在它上面,該做些什麼呢?世界有多大,你能看多遠?為什麼在每次浪潮到來時你都無法預想到,而感嘆這世界變化如此之快?

我對微軟的發展的一些看法:

微軟把.NET擴展到高端市場和移動設備市場,為.NET開發的程序可以在基於.NET的任何設備上都可以運行,大家不需要為不同的設備用不同的工具開發應用,應用極大的推動了基礎軟體的擴大,就象OFFICE,SQL Server輔助擴大了Windows的銷售一樣.

未來的XBOX也會變成.NET平台,成為家庭連網的安全網關和交易網關和信息網關,如果你覺得微軟進入游戲業就是為了眼饞游戲這塊利潤,那你就大錯特錯了,這個皮毛根本不值得微軟大動這么財力.

PDA和手機也和機頂盒一樣嵌入.NET,你打開電視,你打電話,你玩游戲,你工作,你上網,你甚至打開冰箱,你都不會知道在背後支撐的是.NET,從高端伺服器到你的手機,全部是微軟的軟體這是一個偉大的設想,如果微軟能夠兢兢業業的走,憑這樣的財力人力和管理和經營戰略,走10年,實現的可能性非常大,這不是以個人意志為轉移的,你說他倒他就會倒嗎?

如果會成功,當然微軟會成為人類歷史上最偉大的公司,賺取的財富已經不能再提,最關鍵的問題是:我們全人類的生活和工作被一個私人的商業公司所控制著.

只是到那個恐怖的地步,你是否有勇氣和能力把他拆分.因為他足以觸及到你的生活和工作,社會的經濟,政治活動,甚至軍事,任何的動作都足以引起社會的大地震.你認為他有什麼理由完不成這些夢想嗎?

❺ java 代碼用dbcp 怎麼替換

1,連接池創建
BasicDataSource -> DataSource
@Override
public Connection getConnection()
【a】createDataSource()
如果dataSource不為空,則返回數據源對象,否則創建之,如下:
【1】createConnectionFactory()
(a)通過配置參數<property name="driverClassName" value="${jdbc.driver}" />,載入驅動類Class.forName(driverClassName);
(b)通過配置參數<property name="url" value="${jdbc.url}" />,獲取驅動DriverManager.getDriver(url);
(c)通過配置參數<property name="username" value="${jdbc.username}" />,<property name="password" value="${jdbc.password}" />,
以及driver,url,創建資料庫連接工廠new DriverConnectionFactory(driver, url, connectionProperties);
【2】createConnectionPool()
(a)通過配置參數:<property name="maxActive" value="${dbcp.maxActive}" />
<property name="maxIdle" value="${dbcp.maxIdle}" />
<property name="minIdle" value="${dbcp.minIdle}" />
等配置項,創建連接池org.apach.commons.pool.impl.GenericObjectPool connectionPool
commons-dbcp本身不創建連接池,通過commons-pool來管理連接池
(b)GenericObjectPool.addObject()中調用下步創建的連接池工廠類,創建連接,並通過addObjectToPool(obj, false);將連接保存在連接池
【4】(driverConnectionFactory, statementPoolFactory, abandonedConfig)
(a)創建連接池工廠類PoolableConnectionFactory,工廠類內部將該工廠設置到上步創建的connectionPool中,這樣就可以通過connectionPool中的addObject()調用連接池工廠創建連接
【5】createDataSourceInstance()
(a)根據連接池connectionPool創建池化數據源對象 PoolingDataSource pds = new PoolingDataSource(connectionPool)
【6】初始化連接
for (int i = 0 ; i < initialSize ; i++) {
connectionPool.addObject();
}
【7】返回池化資料庫連接對象dataSource
【b】getConnection()
【1】_pool.borrowObject();調用【a】-【2】創建的連接池創建連接
(a)_factory.makeObject();調用【a】-【4】創建的連接池工廠類對象,返回new PoolableConnection(conn,_pool,_config);對象
其中PoolableConnection持有【a】-【2】創建的連接池_pool,當PoolableConnection.close()時,該連接會被_pool回收,_pool.returnObject(this);

❻ Java的有幾種技術架構

Java架構:

軟體架構作為一個概念,體現在技術和業務兩個方面。
從技術角度來說:軟體架構隨著技術的革新不斷地更新其內容,軟體架構建立於當前技術和一些基本原則的基礎之上。
先說一些基本原則:
分層原則:分層是為了降低軟體深度復雜性而使用的關鍵思想,就像社會有了階級一樣,軟體有了層次結構。
模塊化原則:模塊化是化解軟體廣度復雜的必然手段,模塊化的目的就是讓軟體分工。
介面實現分離原則隨著軟體模塊化的不斷深入改進,面向介面編程而不是面向實現編程可以讓復雜度日趨增高的軟體降低模塊之間的耦合度,從而讓各模塊更輕松改進。從這個原則出發,軟體也從微觀進行了細致的規范化。
還有兩個比較小但很重要的原則:
細節隱藏原則很顯然把復雜問題簡化,把難看的細節隱去,能讓軟體結構更清晰。其實這個原則使用很普遍,java/c++語言中的封裝原則以及設計模式中的Facade(外觀)模式就很能體現這個原則的精神。
依賴倒置原則隨著軟體結構的進一步發展,層與層之間、模塊與模塊之間的依賴逐漸加深,而層、模塊的動態可插拔要求不端增大。依賴倒置原則可看視為介面實現分離原則的深化,根據此原則的精神,軟體進入了工具時代。這個原則有點類似於知名的好萊塢法則:Don't call us, we'll call you。

以上這些原則奠定了我們的軟體架構的價值指標。但軟體架構畢竟是建立在當前技術之上的。而每一代技術都有架構模式。過去的不再說了,讓我們現在就來看一下當前流行的技術,以及當前我們能採用的架構。

因為面向對象是當前最流行開發技術,且設計模式的大量使用使面向對象的走向成熟,而資料庫是當前最有效的存儲結構、web界面是當前最流行的用戶介面,所以當前最典型的三層次架構就架構在以上幾項技術的基礎之上,用資料庫作存儲層、用面向對象來實現業務層、用web來作為用戶介面層。我們從三層次架構談起:
因為面向對象技術和資料庫技術不適配,所以在標准三層次架構的基礎上,我們增加了數據持久層,來管理O-R雙向映射,但目前一直沒有最理想的實現技術。cmp和entity bean技術因為其實現復雜,功能前景有限,已接近被淘汰的邊緣。JDO及hibernate作為o-r映射的後期之秀,尤其是hibernate,功能相當完備。推薦作為持久層的首選
在業務層,因為當前業務日趨負載,且變動頻繁,所以我們必須有足夠敏捷的技術來保證我們的適應變化的能力,在標准j2ee系統中session bean負責業務處理,且有不錯的性能表現,但採用ejb系統對業務架構模式改變太大,且其復雜而昂貴,業務代碼移植性差。而spring 作為一個bean配置的輕量級架構,漂亮的IOC模式實現,對業務架構影響小,所以推薦作為中間層業務框架。
在用戶結構層,雖然servlet/jsp/jstl/javaBean 能夠實現MVC架構,但終究過於粗糙。struts對MVC架構的實現就比較完美,Taperstry也極好地實現MVC架構,且採用基於事件的方式,非常誘人,惜其不夠成熟,我們仍舊推薦struts作為用戶介面層基礎架構。
因為業務層是三層次架構中最有決定意義的,所以讓我們回到業務層細致地分析一下,在復雜的業務我們常常需要以下基礎服務的一種或幾種:事務一致性服務acid(tool:jta/jts)、並發加鎖服務concurrent&&lock、池化管理服務cache、訪問控制服務(tool:jaas)、流程式控制制服務workflow、動態實現服務IOC,串列化消息服務(tool:jms)、負載平衡服務blance等。如果我們不採用重量級應用伺服器(如weblogic,websphere,jboss等)及重量級組件(EJB),我們必須自己實現其中一些服務。雖然我們大多情況下,不需要所有這些服務,但實現起來卻非易事。幸運的是我們有大量的開源實現代碼,但採用開源代碼卻常常是件不輕松的事。

隨著xml作為結構化信息傳輸和存儲地位日漸重要,一些xml文檔操作工具(DOM,Digester,SAX等)的使用愈發重要,而隨著xml schema的java binding工具(jaxb,xmlbean等)工具的成熟,採用xml schema來設計xml文檔格式,然後採用java binding來生成java bean 會成為主要編程模式,而這又進一步使數據中心向xml轉移,使在中小數據量上,愈發傾向於以xquery為查詢語言的xml資料庫。最近還有一個趨勢,microsoft,ibm等紛紛大量開發中間軟體如(microsoft office之infopath),可以直接從xml schema 生成 錄入頁面等非常實用的功能。還有web service 的廣泛應用,都將對軟體的架構有非常重大的影響。至於面向服務架構(SOA)前景如何,三層次架構什麼時候走入歷史,現在還很難定論。

aop的發展也會對軟體架構有很深的影響,但在面向對象架構里,無論aspectJ還是jboss-aop抑是aspectWerks、nanning都有其自身的嚴重問題:維護性很差,所以說它將很難走遠。也許作為一個很好的思想,它將在web service里大展身手。

rdf,owl作為w3c語義模型的標志性的語言,也很難想像能在當前業務架構發揮太大影響。但如果真如它所聲稱那樣,廣泛地改變著信息的結構。那麼對軟體架構也會有深遠影響。

有關架構設計的一些忠告:
盡量建立完整的持久對象層.可獲得高回報
盡量將各功能分層,分塊,每一模塊均依賴假定的其它模塊的外觀
不能依賴靜態數據來實現IOC模式,應該依賴數據特徵介面,靜態數據僅是數據特徵介面實現方式之一
架構設計時xml是支持而不是依賴.但可以提供單一的xml版本的實現

從業務角度說:軟體架構應是深刻體現業務內部規則的業務架構,但因為業務變化頻紝,所以軟體架構很難保持恆定不變,但業務的頻繁變化不應是軟體架構大規模頻繁變化的原因,軟體架構應是基於變化的架構。
一種業務有其在一段時間內穩定存在的理由(暫且不談),業務內部有許多用例,每一種用例都有固定的規則,每一規則都有一些可供判定的項,每一項從某一維度來觀察都是可測量的,我們的架構首先必須保證完美適應每一項每一種測量方式,很多失敗的架構都是因為很多項的測量方式都發生變更這種微觀變化中。

每個用例都有規則,我們在作業務用例分析,常常假定一些規則是先驗的,持久穩定的,然而後來的業務改變常常又證明這種看法是錯誤的,然而常常我們的架構已經為之付出了不可挽回的代價。大量事實證明:規則的變化常常用例變化的根本原因。所以我們的架構要盡可能適應規則的變化,盡可能建立規則模版。

每個用例都關系著不同的角色。每一個用例的產生都必然是因為角色的變更(注意:不是替換,而是增強或減弱),所以注意角色的各種可能情況,對架構的設計有舉足輕重的意義。在我們當前的三層架構里,角色完美地對應介面概念。

在一個系統里很多用例都相互關聯,考慮到每個用例均有可能有不同的特例,所以在架構設計中,盡量採用依賴倒置原則。如架構許可可採用消息通信模式(JMS)。這樣可降低耦合度。

現在我們談一下業務穩定存在理由對業務的影響。存在即是合理,在這里當然是正確的。業務因人而存在,所以問業務存在的理由即是問不同角色的需要這項業務的理由以及喜歡不喜歡當前業務用例的理由,所有這樣的角色都應該在系統里預留。《待續》
在架構設計中有幾個原則可以考慮:
用例盡量細分
用例盡量抽象
角色盡量獨立
項測量獨立原則
追求簡單性
這里未提供相關的例子,例子會在以後的更新時提供。

業務和模式之間的關系
業務中的一些用例之間的關系常常和一些常規的模式很相似。但隨著時間的演化,慢慢地和先前的模式有了分歧。這是個正常的現象。但這對系統架構卻要求非常高,要求系統架構能適應一些模式的更替。在這里我們盡可能早地注意到用例之間的相互角色變化,為架構更新做好准備.

❼ Java線程池中的核心線程是如何被重復利用的

Java線程池中的核心線程是如何被重復利用的?

引言

在Java開發中,經常需要創建線程去執行一些任務,實現起來也非常方便,但如果並發的線程數量很多,並且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,因為頻繁創建線程和銷毀線程需要時間。此時,我們很自然會想到使用線程池來解決這個問題。

使用線程池的好處:

  • 降低資源消耗。java中所有的池化技術都有一個好處,就是通過復用池中的對象,降低系統資源消耗。設想一下如果我們有n多個子任務需要執行,如果我們為每個子任務都創建一個執行線程,而創建線程的過程是需要一定的系統消耗的,最後肯定會拖慢整個系統的處理速度。而通過線程池我們可以做到復用線程,任務有多個,但執行任務的線程可以通過線程池來復用,這樣減少了創建線程的開銷,系統資源利用率得到了提升。

  • 降低管理線程的難度。多線程環境下對線程的管理是最容易出現問題的,而線程池通過框架為我們降低了管理線程的難度。我們不用再去擔心何時該銷毀線程,如何最大限度的避免多線程的資源競爭。這些事情線程池都幫我們代勞了。

  • 提升任務處理速度。線程池中長期駐留了一定數量的活線程,當任務需要執行時,我們不必先去創建線程,線程池會自己選擇利用現有的活線程來處理任務。

  • 很顯然,線程池一個很顯著的特徵就是「長期駐留了一定數量的活線程」,避免了頻繁創建線程和銷毀線程的開銷,那麼它是如何做到的呢?我們知道一個線程只要執行完了run()方法內的代碼,這個線程的使命就完成了,等待它的就是銷毀。既然這是個「活線程」,自然是不能很快就銷毀的。為了搞清楚這個「活線程」是如何工作的,下面通過追蹤源碼來看看能不能解開這個疑問。

    分析方法

    在分析源碼之前先來思考一下要怎麼去分析,源碼往往是比較復雜的,如果知識儲備不夠豐厚,很有可能會讀不下去,或者讀岔了。一般來講要時刻緊跟著自己的目標來看代碼,跟目標關系不大的代碼可以不理會它,一些異常的處理也可以暫不理會,先看正常的流程。就我們現在要分析的源碼而言,目標就是看看線程是如何被復用的。那麼對於線程池的狀態的管理以及非正常狀態下的處理代碼就可以不理會,具體來講,在ThreadPollExcutor類中,有一個欄位private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));是對線程池的運行狀態和線程池中有效線程的數量進行控制的, 它包含兩部分信息: 線程池的運行狀態 (runState) 和線程池內有效線程的數量 (workerCount),還有幾個對ctl進行計算的方法:

  • // 獲取運行狀態

  • private static int runStateOf(int c) { return c & ~CAPACITY; }


  • // 獲取活動線程數

  • private static int workerCountOf(int c) { return c & CAPACITY; }123456

  • 以上兩個方法在源碼中經常用到,結合我們的目標,對運行狀態的一些判斷及處理可以不用去管,而對當前活動線程數要加以關注等等。

    下面將遵循這些原則來分析源碼。

    解惑

    當我們要向線程池添加一個任務時是調用ThreadPollExcutor對象的execute(Runnable command)方法來完成的,所以先來看看ThreadPollExcutor類中的execute(Runnable command)方法的源碼:

  • public void execute(Runnable command) {

  • if (command == null)

  • throw new NullPointerException();


  • int c = ctl.get();

  • if (workerCountOf(c) < corePoolSize) {

  • if (addWorker(command, true))

  • return;

  • c = ctl.get();

  • }

  • if (isRunning(c) && workQueue.offer(command)) {

  • int recheck = ctl.get();

  • if (! isRunning(recheck) && remove(command))

  • reject(command);

  • else if (workerCountOf(recheck) == 0)

  • addWorker(null, false);

  • }

  • else if (!addWorker(command, false))

  • reject(command);

  • }

  • 按照我們在分析方法中提到的一些原則,去掉一些相關性不強的代碼,看看核心代碼是怎樣的。

  • // 為分析而簡化後的代碼

  • public void execute(Runnable command) {


  • int c = ctl.get();

  • if (workerCountOf(c) < corePoolSize) {

  • // 如果當前活動線程數小於corePoolSize,則新建一個線程放入線程池中,並把任務添加到該線程中

  • if (addWorker(command, true))

  • return;

  • c = ctl.get();

  • }


  • // 如果當前活動線程數大於等於corePoolSize,則嘗試將任務放入緩存隊列

  • if (workQueue.offer(command)) {

  • int recheck = ctl.get();

  • if (workerCountOf(recheck) == 0)

  • addWorker(null, false);

  • }else {

  • // 緩存已滿,新建一個線程放入線程池,並把任務添加到該線程中(此時新建的線程相當於非核心線程)

  • addWorker(command, false)

  • }

  • }22

  • 這樣一看,邏輯應該清晰很多了。

  • 如果 當前活動線程數 < 指定的核心線程數,則創建並啟動一個線程來執行新提交的任務(此時新建的線程相當於核心線程);

  • 如果 當前活動線程數 >= 指定的核心線程數,且緩存隊列未滿,則將任務添加到緩存隊列中;

  • 如果 當前活動線程數 >= 指定的核心線程數,且緩存隊列已滿,則創建並啟動一個線程來執行新提交的任務(此時新建的線程相當於非核心線程);

  • 接下來看addWorker(Runnable firstTask, boolean core)方法

  • private boolean addWorker(Runnable firstTask, boolean core) {

  • retry:

  • for (;;) {

  • int c = ctl.get();

  • int rs = runStateOf(c);


  • // Check if queue empty only if necessary.

  • if (rs >= SHUTDOWN &&

  • ! (rs == SHUTDOWN &&

  • firstTask == null &&

  • ! workQueue.isEmpty()))

  • return false;


  • for (;;) {

  • int wc = workerCountOf(c);

  • if (wc >= CAPACITY ||

  • wc >= (core ? corePoolSize : maximumPoolSize))

  • return false;

  • if ((c))

  • break retry;

  • c = ctl.get(); // Re-read ctl

  • if (runStateOf(c) != rs)

  • continue retry;

  • // else CAS failed e to workerCount change; retry inner loop

  • }

  • }


  • boolean workerStarted = false;

  • boolean workerAdded = false;

  • Worker w = null;

  • try {

  • w = new Worker(firstTask);

  • final Thread t = w.thread;

  • if (t != null) {

  • final ReentrantLock mainLock = this.mainLock;

  • mainLock.lock();

  • try {

  • // Recheck while holding lock.

  • // Back out on ThreadFactory failure or if

  • // shut down before lock acquired.

  • int rs = runStateOf(ctl.get());


  • if (rs < SHUTDOWN ||

  • (rs == SHUTDOWN && firstTask == null)) {

  • if (t.isAlive()) // precheck that t is startable

  • throw new IllegalThreadStateException();

  • workers.add(w);

  • int s = workers.size();

  • if (s > largestPoolSize)

  • largestPoolSize = s;

  • workerAdded = true;

  • }

  • } finally {

  • mainLock.unlock();

  • }

  • if (workerAdded) {

  • t.start();

  • workerStarted = true;

  • }

  • }

  • } finally {

  • if (! workerStarted)

  • addWorkerFailed(w);

  • }

  • return workerStarted;

  • }

  • 同樣,我們也來簡化一下:

  • // 為分析而簡化後的代碼

  • private boolean addWorker(Runnable firstTask, boolean core) {


  • int wc = workerCountOf(c);

  • if (wc >= (core ? corePoolSize : maximumPoolSize))

  • // 如果當前活動線程數 >= 指定的核心線程數,不創建核心線程

  • // 如果當前活動線程數 >= 指定的最大線程數,不創建非核心線程

  • return false;


  • boolean workerStarted = false;

  • boolean workerAdded = false;

  • Worker w = null;

  • try {

  • // 新建一個Worker,將要執行的任務作為參數傳進去

  • w = new Worker(firstTask);

  • final Thread t = w.thread;

  • if (t != null) {

  • workers.add(w);

  • workerAdded = true;

  • if (workerAdded) {

  • // 啟動剛剛新建的那個worker持有的線程,等下要看看這個線程做了啥

  • t.start();

  • workerStarted = true;

  • }

  • }

  • } finally {

  • if (! workerStarted)

  • addWorkerFailed(w);

  • }

  • return workerStarted;

  • }2223242526272829303132

  • 看到這里,我們大概能猜測到,addWorker方法的功能就是新建一個線程並啟動這個線程,要執行的任務應該就是在這個線程中執行。為了證實我們的這種猜測需要再來看看Worker這個類。

  • private final class Worker

  • extends AbstractQueuedSynchronizer

  • implements Runnable{

  • // ....

  • }


  • Worker(Runnable firstTask) {

  • setState(-1); // inhibit interrupts until runWorker

  • this.firstTask = firstTask;

  • this.thread = getThreadFactory().newThread(this);

  • }123456789101112

  • 從上面的Worker類的聲明可以看到,它實現了Runnable介面,以及從它的構造方法中可以知道待執行的任務賦值給了它的變數firstTask,並以它自己為參數新建了一個線程賦值給它的變數thread,那麼運行這個線程的時候其實就是執行Worker的run()方法,來看一下這個方法:

  • public void run() {

  • runWorker(this);

  • }


  • final void runWorker(Worker w) {

  • Thread wt = Thread.currentThread();

  • Runnable task = w.firstTask;

  • w.firstTask = null;

  • w.unlock(); // allow interrupts

  • boolean completedAbruptly = true;

  • try {

  • while (task != null || (task = getTask()) != null) {

  • w.lock();

  • // If pool is stopping, ensure thread is interrupted;

  • // if not, ensure thread is not interrupted. This

  • // requires a recheck in second case to deal with

  • // shutdownNow race while clearing interrupt

  • if ((runStateAtLeast(ctl.get(), STOP) ||

  • (Thread.interrupted() &&

  • runStateAtLeast(ctl.get(), STOP))) &&

  • !wt.isInterrupted())

  • wt.interrupt();

  • try {

  • beforeExecute(wt, task);

  • Throwable thrown = null;

  • try {

  • task.run();

  • } catch (RuntimeException x) {

  • thrown = x; throw x;

  • } catch (Error x) {

  • thrown = x; throw x;

  • } catch (Throwable x) {

  • thrown = x; throw new Error(x);

  • } finally {

  • afterExecute(task, thrown);

  • }

  • } finally {

  • task = null;

  • w.completedTasks++;

  • w.unlock();

  • }

  • }

  • completedAbruptly = false;

  • } finally {

  • processWorkerExit(w, completedAbruptly);

  • }

  • }04142434445464748

  • 在run()方法中只調了一下 runWorker(this) 方法,再來簡化一下這個 runWorker() 方法

  • // 為分析而簡化後的代碼

  • final void runWorker(Worker w) {

  • Runnable task = w.firstTask;

  • w.firstTask = null;

  • while (task != null || (task = getTask()) != null) {

  • try {

  • task.run();

  • } finally {

  • task = null;

  • }

  • }

  • }12345678910111213

  • 很明顯,runWorker()方法裡面執行了我們新建Worker對象時傳進去的待執行的任務,到這里為止貌似這個worker的run()方法就執行完了,既然執行完了那麼這個線程也就沒用了,只有等待虛擬機銷毀了。那麼回顧一下我們的目標:Java線程池中的核心線程是如何被重復利用的?好像並沒有重復利用啊,新建一個線程,執行一個任務,然後就結束了,銷毀了。沒什麼特別的啊,難道有什麼地方漏掉了,被忽略了?再仔細看一下runWorker()方法的代碼,有一個while循環,當執行完firstTask後task==null了,那麼就會執行判斷條件(task = getTask()) != null,我們假設這個條件成立的話,那麼這個線程就不止只執行一個任務了,可以執行多個任務了,也就實現了重復利用了。答案呼之欲出了,接著看getTask()方法

  • private Runnable getTask() {

  • boolean timedOut = false; // Did the last poll() time out?


  • for (;;) {

  • int c = ctl.get();

  • int rs = runStateOf(c);


  • // Check if queue empty only if necessary.

  • if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {

  • decrementWorkerCount();

  • return null;

  • }


  • int wc = workerCountOf(c);


  • // Are workers subject to culling?

  • boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;


  • if ((wc > maximumPoolSize || (timed && timedOut))

  • && (wc > 1 || workQueue.isEmpty())) {

  • if ((c))

  • return null;

  • continue;

  • }


  • try {

  • Runnable r = timed ?

  • workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :

  • workQueue.take();

  • if (r != null)

  • return r;

  • timedOut = true;

  • } catch (InterruptedException retry) {

  • timedOut = false;

  • }

  • }

  • }

  • 老規矩,簡化一下代碼來看:

  • // 為分析而簡化後的代碼

  • private Runnable getTask() {

  • boolean timedOut = false;

  • for (;;) {

  • int c = ctl.get();

  • int wc = workerCountOf(c);


  • // timed變數用於判斷是否需要進行超時控制。

  • // allowCoreThreadTimeOut默認是false,也就是核心線程不允許進行超時;

  • // wc > corePoolSize,表示當前線程池中的線程數量大於核心線程數量;

  • // 對於超過核心線程數量的這些線程,需要進行超時控制

  • boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;


  • if (timed && timedOut) {

  • // 如果需要進行超時控制,且上次從緩存隊列中獲取任務時發生了超時,那麼嘗試將workerCount減1,即當前活動線程數減1,

  • // 如果減1成功,則返回null,這就意味著runWorker()方法中的while循環會被退出,其對應的線程就要銷毀了,也就是線程池中少了一個線程了

  • if ((c))

  • return null;

  • continue;

  • }


  • try {

  • Runnable r = timed ?

  • workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :

  • workQueue.take();


  • // 注意workQueue中的poll()方法與take()方法的區別

  • //poll方式取任務的特點是從緩存隊列中取任務,最長等待keepAliveTime的時長,取不到返回null

  • //take方式取任務的特點是從緩存隊列中取任務,若隊列為空,則進入阻塞狀態,直到能取出對象為止


  • if (r != null)

  • return r;

  • timedOut = true;

  • } catch (InterruptedException retry) {

  • timedOut = false;

  • }

  • }

  • }39

  • 從以上代碼可以看出,getTask()的作用是

  • 如果當前活動線程數大於核心線程數,當去緩存隊列中取任務的時候,如果緩存隊列中沒任務了,則等待keepAliveTime的時長,此時還沒任務就返回null,這就意味著runWorker()方法中的while循環會被退出,其對應的線程就要銷毀了,也就是線程池中少了一個線程了。因此只要線程池中的線程數大於核心線程數就會這樣一個一個地銷毀這些多餘的線程。

  • 如果當前活動線程數小於等於核心線程數,同樣也是去緩存隊列中取任務,但當緩存隊列中沒任務了,就會進入阻塞狀態,直到能取出任務為止,因此這個線程是處於阻塞狀態的,並不會因為緩存隊列中沒有任務了而被銷毀。這樣就保證了線程池有N個線程是活的,可以隨時處理任務,從而達到重復利用的目的。

  • 小結

    通過以上的分析,應該算是比較清楚地解答了「線程池中的核心線程是如何被重復利用的」這個問題,同時也對線程池的實現機制有了更進一步的理解:

  • 當有新任務來的時候,先看看當前的線程數有沒有超過核心線程數,如果沒超過就直接新建一個線程來執行新的任務,如果超過了就看看緩存隊列有沒有滿,沒滿就將新任務放進緩存隊列中,滿了就新建一個線程來執行新的任務,如果線程池中的線程數已經達到了指定的最大線程數了,那就根據相應的策略拒絕任務。

  • 當緩存隊列中的任務都執行完了的時候,線程池中的線程數如果大於核心線程數,就銷毀多出來的線程,直到線程池中的線程數等於核心線程數。此時這些線程就不會被銷毀了,它們一直處於阻塞狀態,等待新的任務到來。

  • 注意:
    本文所說的「核心線程」、「非核心線程」是一個虛擬的概念,是為了方便描述而虛擬出來的概念,在代碼中並沒有哪個線程被標記為「核心線程」或「非核心線程」,所有線程都是一樣的,只是當線程池中的線程多於指定的核心線程數量時,會將多出來的線程銷毀掉,池中只保留指定個數的線程。那些被銷毀的線程是隨機的,可能是第一個創建的線程,也可能是最後一個創建的線程,或其它時候創建的線程。一開始我以為會有一些線程被標記為「核心線程」,而其它的則是「非核心線程」,在銷毀多餘線程的時候只銷毀那些「非核心線程」,而「核心線程」不被銷毀。這種理解是錯誤的。

    另外還有一個重要的介面 BlockingQueue 值得去了解,它定義了一些入隊出隊同步操作的方法,還可以阻塞,作用很大。

❽ java 系統架構

開始的架構設計也是最難的,需要調研同類產品的情況以及技術特徵,了解當前世界上對這種產品所能提供的理論支持和技術平台支持,再結合自己項目的特點(需要透徹的系統分析),才能逐步形成自己項目的架構藍圖。
比如要開發網站引擎系統,就從Yahoo的個人主頁生成工具 到虛擬主機商提供的網站自動生成系統,以及IBM Webphere Portal的特點和局限 從而從架構設計角度定立自己產品的位置。

好的設計肯定需要經過反復修改,從簡單到復雜的循環測試是保證設計正確的一個好辦法。

由於在開始選擇了正確的方向,後來項目的實現過程也驗證了這種選擇,但在一些架構設計的細部方面,還需要對方案進行修改,屬於那種螺旋上升的方式,顯然這是通過測試第一的思想和XP工程方法來實現的。

如果我們開始的架構設計在技術平台定位具有一定的世界先進水平,那麼,項目開發實際有一半相當於做實驗,是研發,存在相當的技術風險。

因此,一開始我們不可能將每個需求都實現,而是採取一種簡單完成架構流程的辦法,使用最簡單的需求將整個架構都簡單的完成一遍(加入人工干 預),以檢驗各個技術環節是否能協調配合工作(非常優秀先進的兩種技術有時無法在一起工作),同時也可以探知技術的深淺,掌握項目中的技術難易點。這個過 程完成後,我們就對設計方案做出上面的重大修改,豐富完善了設計方案。

設計模式是支撐架構的重要組件

架構設計也類似一種工作流,它是動態的,這點不象建築設計那樣,一開始就能完全確定,架構設計伴隨著整個項目的進行過程之中,有兩種具體操作保證架構設計的正確完成,那就是設計模式(靜態)和工程項目方法(RUP或XP 動態的)。

設計模式是支撐架構的一種重要組件,這與建築有很相象的地方,一個建築物建立設計需要建築架構設計,在具體施工中,有很多建築方面的規則和模式。

我們從J2EE藍圖模式分類http://java.sun.com/blueprints/patterns/catalog.html中就可以很清楚的看到J2EE這樣一個框架軟體的架構與設計模式的關系。

架構設計是骨架,設計模式就是肉

這樣,一個比較豐富的設計方案可以交由程序員進一步完成了,載輔助以適當的工程方法,這樣就可保證項目的架構設計能正確快速的完成。

時刻牢記架構設計的目標

由於架構設計是在動態中完成的,因此在把握架構設計的目標上就很重要,因此在整個項目過程中,甚至每一步我們都必須牢記我們架構設計的總體目標,可以概括下面幾點:

1. 最大化的重用:這個重用包括組件重用 和設計模式使用等多個方面。

比如,我們項目中有用戶注冊和用戶許可權系統驗證,這其實是個通用課題,每個項目只是有其內容和一些細微的差別,如果我們之前有這方面成功研發經 驗,可以直接重用,如果沒有,那麼我們就要進行這個子項目的研發,在研發過程中,不能僅僅看到這個項目的需求,也要以架構的概念去完成這個可以稱為組件的 子項目。

2. 盡可能的簡單明了:我們解決問題的總方向是將復雜問題簡單化,其實這也是中間件或多層體系技術的根本目標。但是在具體實施設計過程中,我們可能會將簡單問題復雜化,特別是設計模式的運用上很容易范這個錯誤,因此如何盡可能的做到設計的簡單明了是不容易的。

我認為落實到每個類的具體實現上要真正能體現系統事物的本質特徵,因為事物的本質特徵只有一個,你的代碼越接近它,表示你的設計就是簡單明了, 越簡單明了,你的系統就越可靠。更多情況是,一個類並不能反應事物本質,需要多個類的組合協調,那麼能夠正確使用合適的設計模式就稱為重中之重。

我們看一個具備好的架構設計的系統代碼時,基本看到的都是設計模式,寵物店(pet store)就是這樣的例子。或者可以這樣說,一個好的架構設計基本是由簡單明了的多個設計模式完成的。

3. 最靈活的拓展性:架構設計要具備靈活性 拓展性,這樣,用戶可以在你的架構上進行二次開發或更加具體的開發。

要具備靈活的拓展性,就要站在理論的高度去進行架構設計,比如現在工作流概念逐步流行,因為我們具體很多實踐項目中都有工作流的影子,工作流中有一個樹形結構許可權設定的概念就對很多領域比較通用。

樹形結構是組織信息的基本形式,我們現在看到的網站或者ERP前台都是以樹形菜單來組織功能的,那麼我們在進行架構設計時,就可以將樹形結構和 功能分開設計,他們之間聯系可以通過樹形結構的節點link在一起,就象我們可以在聖誕樹的樹枝上掛各種小禮品一樣,這些小禮品就是我們要實現的各種功 能。

有了這個概念,通常比較難實現的用戶級別許可權控制也有了思路,將具體用戶或組也是和樹形結構的節點link在一起,這樣就間接實現了用戶對相應功能的許可權控制,有了這樣的基本設計方案的架構無疑具備很靈活的拓展性。

Java架構設計

軟體架構作為一個概念,體現在技術和業務兩個方面。

從技術角度來說:軟體架構隨著技術的革新不斷地更新其內容,軟體架構建立於當前技術和一些基本原則的基礎之上。

先說一些基本原則:

分層原則:分層是為了降低軟體深度復雜性而使用的關鍵思想,就像社會有了階級一樣,軟體有了層次結構。
模塊化原則:模塊化是化解軟體廣度復雜的必然手段,模塊化的目的就是讓軟體分工。
介面實現分離原則隨著軟體模塊化的不斷深入改進,面向介面編程而不是面向實現編程可以讓復雜度日趨增高的軟體降低模塊之間的耦合度,從而讓各模塊更輕松改進。從這個原則出發,軟體也從微觀進行了細致的規范化。

還有兩個比較小但很重要的原則:

細節隱藏原則很顯然把復雜問題簡化,把難看的細節隱去,能讓軟體結構更清晰。其實這個原則使用很普遍,java/c++語言中的封裝原則以及設計模式中的Facade(外觀)模式就很能體現這個原則的精神。

依賴倒置原則隨著軟體結構的進一步發展,層與層之間、模塊與模塊之間的依賴逐漸加深,而層、模塊的動態可插拔要求不端增大。依賴倒置原則可看視 為介面實現分離原則的深化,根據此原則的精神,軟體進入了工具時代。這個原則有點類似於知名的好萊塢法則:Don't call us, we'll call you。

以上這些原則奠定了我們的軟體架構的價值指標。但軟體架構畢竟是建立在當前技術之上的。而每一代技術都有架構模式。過去的不再說了,讓我們現在就來看一下當前流行的技術,以及當前我們能採用的架構。

因為面向對象是當前最流行開發技術,且設計模式的大量使用使面向對象的走向成熟,而資料庫是當前最有效的存儲結構、web界面是當前最流行的用 戶介面,所以當前最典型的三層次架構就架構在以上幾項技術的基礎之上,用資料庫作存儲層、用面向對象來實現業務層、用web來作為用戶介面層。我們從三層 次架構談起:

因為面向對象技術和資料庫技術不適配,所以在標准三層次架構的基礎上,我們增加了數據持久層,來管理O-R雙向映射,但目前一直沒有最理想的實 現技術。cmp和entity bean技術因為其實現復雜,功能前景有限,已接近被淘汰的邊緣。JDO及hibernate作為o-r映射的後期之秀,尤其是hibernate,功能 相當完備。推薦作為持久層的首選

在業務層,因為當前業務日趨負載,且變動頻繁,所以我們必須有足夠敏捷的技術來保證我們的適應變化的能力,在標准j2ee系統中session bean負責業務處理,且有不錯的性能表現,但採用ejb系統對業務架構模式改變太大,且其復雜而昂貴,業務代碼移植性差。而spring 作為一個bean配置的輕量級架構,漂亮的IOC模式實現,對業務架構影響小,所以推薦作為中間層業務框架。

在用戶結構層,雖然servlet/jsp/jstl/javaBean 能夠實現MVC架構,但終究過於粗糙。struts對MVC架構的實現就比較完美,Taperstry也極好地實現MVC架構,且採用基於事件的方式,非 常誘人,惜其不夠成熟,我們仍舊推薦struts作為用戶介面層基礎架構。

因為業務層是三層次架構中最有決定意義的,所以讓我們回到業務層細致地分析一下,在復雜的業務我們常常需要以下基礎服務的一種或幾種:事務一致 性服務acid(tool:jta/jts)、並發加鎖服務concurrent&&lock、池化管理服務cache、訪問控制服務 (tool:jaas)、流程式控制制服務workflow、動態實現服務IOC,串列化消息服務(tool:jms)、負載平衡服務blance等。如果我 們不採用重量級應用伺服器(如weblogic,websphere,jboss等)及重量級組件(EJB),我們必須自己實現其中一些服務。雖然我們大 多情況下,不需要所有這些服務,但實現起來卻非易事。幸運的是我們有大量的開源實現代碼,但採用開源代碼卻常常是件不輕松的事。

隨著xml作為結構化信息傳輸和存儲地位日漸重要,一些xml文檔操作工具(DOM,Digester,SAX等)的使用愈發重要,而隨著 xml schema的java binding工具(jaxb,xmlbean等)工具的成熟,採用xml schema來設計xml文檔格式,然後採用java binding來生成java bean 會成為主要編程模式,而這又進一步使數據中心向xml轉移,使在中小數據量上,愈發傾向於以xquery為查詢語言的xml資料庫。最近還有一個趨勢, microsoft,ibm等紛紛大量開發中間軟體如(microsoft office之infopath),可以直接從xml schema 生成 錄入頁面等非常實用的功能。還有web service 的廣泛應用,都將對軟體的架構有非常重大的影響。至於面向服務架構(SOA)前景如何,三層次架構什麼時候走入歷史,現在還很難定論。

aop的發展也會對軟體架構有很深的影響,但在面向對象架構里,無論aspectJ還是jboss-aop抑是aspectWerks、 nanning都有其自身的嚴重問題:維護性很差,所以說它將很難走遠。也許作為一個很好的思想,它將在web service里大展身手。

rdf,owl作為w3c語義模型的標志性的語言,也很難想像能在當前業務架構發揮太大影響。但如果真如它所聲稱那樣,廣泛地改變著信息的結構。那麼對軟體架構也會有深遠影響。

有關架構設計的一些忠告:

盡量建立完整的持久對象層.可獲得高回報
盡量將各功能分層,分塊,每一模塊均依賴假定的其它模塊的外觀
不能依賴靜態數據來實現IOC模式,應該依賴數據特徵介面,靜態數據僅是數據特徵介面實現方式之一
架構設計時xml是支持而不是依賴.但可以提供單一的xml版本的實現

從業務角度說:軟體架構應是深刻體現業務內部規則的業務架構,但因為業務變化頻紝,所以軟體架構很難保持恆定不變,但業務的頻繁變化不應是軟體架構大規模頻繁變化的原因,軟體架構應是基於變化的架構。

一種業務有其在一段時間內穩定存在的理由(暫且不談),業務內部有許多用例,每一種用例都有固定的規則,每一規則都有一些可供判定的項,每一項 從某一維度來觀察都是可測量的,我們的架構首先必須保證完美適應每一項每一種測量方式,很多失敗的架構都是因為很多項的測量方式都發生變更這種微觀變化 中。

每個用例都有規則,我們在作業務用例分析,常常假定一些規則是先驗的,持久穩定的,然而後來的業務改變常常又證明這種看法是錯誤的,然而常常我 們的架構已經為之付出了不可挽回的代價。大量事實證明:規則的變化常常用例變化的根本原因。所以我們的架構要盡可能適應規則的變化,盡可能建立規則模版。

每個用例都關系著不同的角色。每一個用例的產生都必然是因為角色的變更(注意:不是替換,而是增強或減弱),所以注意角色的各種可能情況,對架構的設計有舉足輕重的意義。在我們當前的三層架構里,角色完美地對應介面概念。

在一個系統里很多用例都相互關聯,考慮到每個用例均有可能有不同的特例,所以在架構設計中,盡量採用依賴倒置原則。如架構許可可採用消息通信模式(JMS)。這樣可降低耦合度。

現在我們談一下業務穩定存在理由對業務的影響。存在即是合理,在這里當然是正確的。業務因人而存在,所以問業務存在的理由即是問不同角色的需要這項業務的理由以及喜歡不喜歡當前業務用例的理由,所有這樣的角色都應該在系統里預留。

在架構設計中有幾個原則可以考慮:

用例盡量細分
用例盡量抽象
角色盡量獨立
項測量獨立原則
追求簡單性
這里未提供相關的例子,例子會在以後的更新時提供。

業務和模式之間的關系

業務中的一些用例之間的關系常常和一些常規的模式很相似。但隨著時間的演化,慢慢地和先前的模式有了分歧。這是個正常的現象。但這對系統架構卻要求非常高,要求系統架構能適應一些模式的更替。在這里我們盡可能早地注意到用例之間的相互角色變化,為架構更新做好准備.

❾ java中的修飾符

static 表示靜態,它可以修飾屬性,方法和代碼塊。

1,static修飾屬性(類變數),那麼這個屬性就可以用 類名.屬性名 來訪問,也就是使這個屬性成為本類的類變數,為本類對象所共有。這個屬性就是全類公有。(共有的類變數與對象無關,只和類有關)。

類載入的過程,類本身也是保存在文件中(位元組碼文件保存著類的信息)的,java會通過I/O流把類的文件(位元組碼文件)讀入JVM(java虛擬機),這個過程成為類的載入。JVM(java虛擬機)會通過類路徑(CLASSPATH)來找位元組碼文件。

類變數,會在載入時自動初始化,初始化規則和實例變數相同。

注意:類中的實例變數是在創建對象時被初始化的,被static修飾的屬性,也就是類變數,是在類載入時被創建並進行初始化,類載入的過程是進行一次。也就是類變數只會被創建一次。

2,static修飾方法(靜態方法),會使這個方法成為整個類所公有的方法,可以用類名.方法名 訪問。

注意:static修飾的方法,不直接能訪問(可以通過組合方式訪問)本類中的非靜態(static)成員(包括方法和屬性),本類的非靜態(static)方法可以訪問本類的靜態成員(包括方法和屬性),可以調用靜態方法。靜態方法要慎重使用。在靜態方法中不能出現this關鍵字。

注意:父類中是靜態方法,子類中不能覆蓋為非靜態方法,在符合覆蓋規則的前提下,在父子類中,父類中的靜態方法可以被子類中的靜態方法覆蓋,但是沒有多態。(在使用對象調用靜態方法是其實是調用編譯時類型的靜態方法)

注意:父子類中,靜態方法只能被靜態方法覆蓋,父子類中,非靜態方法只能被非靜態方法覆蓋。

java中的main方法必須寫成static的因為,在類載入時無法創建對象,因為靜態方法可以不通過對象調用
所以在類的main方法。所在在類載入時就可以通過main方法入口來運行程序。

注意:組合方式,就是需要在方法中創建一個所需要的對象,並用這個對象來調用任意所需的該對象的內容,不會再受只能訪問靜態的約束。

3,static修飾初始代碼塊,這時這個初始代碼塊就叫做靜態初始代碼塊,這個代碼塊只在類載入時被執行一次。可以用靜態初始代碼塊初始化一個類。

動態初始代碼塊,寫在類體中的「{}」,這個代碼塊是在生成對象的初始化屬性是運行。這種代碼塊叫動態初始代碼塊。

類在什麼時候會被載入,構造(創建)對象時會載入類,調用類中靜態方法或訪問靜態屬性也是會載入這個靜態方法真正所在的類。在構造子類對象時必會先載入父類,類載入會有延遲載入原則,只有在必須載入時才會載入。

final修飾符,可以修飾變數,方法,類

1,final修飾變數
被fianl修飾的變數就會變成常量(常量應當大寫),一旦賦值不能改變,(可以在初始化時直接賦值,也可以在構造方法里也可以賦值,只能在這兩種方法里二選一,不能不為常量賦值),fianl的常量不會有默認初始值,對於直接在初始化是賦值時final修飾符常和static修飾符一起使用。

2,final修飾方法,被final修飾的方法將不能被其子類覆蓋,保持方法的穩定不能被覆蓋。
3,final修飾類,被final修飾的類將不能被繼承。final類中的方法也都是final的。

注意:final,不能用來修飾構造方法,在父類中如果有常量屬性,在子類中使用常量屬性時是不會進行父類的類載入。靜態常量如果其值可以確定,就不會載入該類,如果不能確定則會載入該常量所在的類。

不變模式,對象一旦創建屬性就不會改變。用final修飾屬性,也用final修飾類(強不變模式),用final修飾屬性(弱不變模式)。

不變模式的典型體現:java.lang.String類,不變模式可以實現對象的共享(可以用一個對象實例賦值給多個對象變數。)

池化的思想,把需要共享的數據放在池中(節省空間,共享數據)
只有String類可以用「」中的字面值創建對象。在String類中,以字面值創建時,會到Java方法空間的串池空間中去查找,如果有就返回串池中字元串的地址,並把這個地址付給對象變數。如果沒有則會在串池裡創建一個字元串對象,並返回其地址付購對象變數,當另一個以字面值創建對象時則會重復上述過程。
如果是new在堆空間中創建String類的對象,則不會有上述的過程。

String類中的intern()方法會將在堆空間中創建的String類對象中的字元串和串池中的比對,如果有相同的串就返回這個串的串池中的地址。

不變模式在對於對象進行修改,添加操作是使相當麻煩的,他會產生很多的中間垃圾對象。創建和銷毀的資源的開銷是相當大的。

String類在字元串連接時會先的效率很低,就是因為它所產生的對象的書性是不能夠修改的,當連接字元串時也就是只能創建新的對象。

對於很多的字元串連接,應當使用StringBuffer類,在使用這個類的對象來進行字元串連接時就不會有多餘的中間對象生成,從而優化了效率。

abstract(抽象)修飾符,可以修飾類和方法

1,abstract修飾類,會使這個類成為一個抽象類,這個類將不能生成對象實例,但可以做為對象變數聲明的類型,也就是編譯時類型,抽象類就像當於一類的半成品,需要子類繼承並覆蓋其中的抽象方法。

2,abstract修飾方法,會使這個方法變成抽象方法,也就是只有聲明(定義)而沒有實現,實現部分以";"代替。需要子類繼承實現(覆蓋)。

注意:有抽象方法的類一定是抽象類。但是抽象類中不一定都是抽象方法,也可以全是具體方法。
abstract修飾符在修飾類時必須放在類名前。

abstract修飾方法就是要求其子類覆蓋(實現)這個方法。調用時可以以多態方式調用子類覆蓋(實現)後的方法,也就是說抽象方法必須在其子類中實現,除非子類本身也是抽象類。

注意:父類是抽象類,其中有抽象方法,那麼子類繼承父類,並把父類中的所有抽象方法都實現(覆蓋)了,子類才有創建對象的實例的能力,否則子類也必須是抽象類。抽象類中可以有構造方法,是子類在構造子類對象時需要調用的父類(抽象類)的構造方法。

final和abstract,private和abstract,static和abstract,這些是不能放在一起的修飾符,因為abstract修飾的方法是必須在其子類中實現(覆蓋),才能以多態方式調用,以上修飾符在修飾方法時期子類都覆蓋不了這個方法,final是不可以覆蓋,private是不能夠繼承到子類,所以也就不能覆蓋,static是可以覆蓋的,但是在調用時會調用編譯時類型的方法,因為調用的是父類的方法,而父類的方法又是抽象的方法,又不能夠調用,所以上的修飾符不能放在一起。

抽象(abstract)方法代表了某種標准,定義標准,定義功能,在子類中去實現功能(子類繼承了父類並需要給出從父類繼承的抽象方法的實現)。
方法一時間想不到怎麼被實現,或有意要子類去實現而定義某種標准,這個方法可以被定義為抽象。(abstract)

模板方法模式

用abstract把制訂標准和實現標准分開,制定的標准就是模板,實現就是按模板標准來實現,也就是繼承模板,實現模板中相應功能的方法。模板中不允許修改的方法可以用fianl來修飾,這個方法不能使抽象方法,為保證安全,封裝,把模板中不公開的部分用protected(保護)修飾。

熱點內容
虎牙安卓版是什麼意思 發布:2024-03-28 17:43:10 瀏覽:859
電腦改成雲伺服器 發布:2024-03-28 17:37:50 瀏覽:265
文件夾審計 發布:2024-03-28 17:08:20 瀏覽:241
密碼反編譯是什麼意思 發布:2024-03-28 17:02:54 瀏覽:309
linux下samba 發布:2024-03-28 16:54:12 瀏覽:539
我的世界國際服手機版免費開伺服器 發布:2024-03-28 16:45:36 瀏覽:284
phpmongodb擴展下載 發布:2024-03-28 16:41:03 瀏覽:323
android開發教程筆記 發布:2024-03-28 16:31:48 瀏覽:771
榮威i6max配置怎麼選 發布:2024-03-28 16:18:11 瀏覽:455
cml編程 發布:2024-03-28 16:14:53 瀏覽:758