JAVAEE項(xiàng)目結(jié)構(gòu)以及并發(fā)隨想
長久以來統(tǒng)領(lǐng)javaee領(lǐng)域的腳手架以spring struts2 mybatis/hibernate引領(lǐng);
Spring:
Spring is not just for Java services。spring作為cgi標(biāo)準(zhǔn)的實(shí)現(xiàn),并不僅僅是作為Java領(lǐng)域的框架,C#平臺依舊可以獲益;spring提供了抽象化等各種方便的注解配置方式或者bootde 一體化方案,極大簡化了Javaee的項(xiàng)目基礎(chǔ);
在spring的使用過程中,兩面分化,一部分,輕量注解,一部分傾向于全注解。
首先注解的前提是必然要經(jīng)歷代理的,動態(tài),靜態(tài),cglib代理。對于輕量注解,角度站在靜態(tài)或者說是一次性注解,
比如controller注解,這些一次性的注解或者是編譯期的注解,在項(xiàng)目上下文初始化作為一個隱射一次性掃描,相關(guān)的有service等類似注解,提供了單例的輕量級對象實(shí)例。視為首選。這樣減少了運(yùn)行期的代理,反射,這些動輒大動干戈的消耗,也為運(yùn)行期的堆棧節(jié)約了更好的資源。
另一類比如responsebody,這類屬于動態(tài)注解或者運(yùn)行期的注解,每次請求,都會執(zhí)行該注解的反射。運(yùn)行期的注解,想當(dāng)然是要占用資源的。
總的來講,不是必須的注解完全可以不注解,基于servlet基礎(chǔ)的request,response方式?jīng)]有解決不了的mvc,取參,傳參,返回等,完全不需要運(yùn)行期的注解,運(yùn)行期的注解看似是減少了代碼量,為了補(bǔ)住這過程的各種缺,會運(yùn)行一個圓環(huán)的動態(tài)注解來執(zhí)行一個被你用在方法內(nèi)部的注解。對于寫在方法里面的param注解,相比于自己用request get 究竟少了哪些代碼?不過是讓原本一步到位的處理,加入了一層代碼攔截。
如何知道一個注解是否是運(yùn)行期或者編譯期的注解,很簡單,Ctrl+鼠標(biāo)點(diǎn)擊,會看見:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
Retention 這個枚舉類型完整清晰的說明了你使用的注解的作用期。
用spring 大家都喜歡用單例,這是極好的方式,單例與并發(fā)本身毫無關(guān)系,除了你非要讓它產(chǎn)生資源標(biāo)識競爭,
如果說你的項(xiàng)目中必須要出現(xiàn)許多prototype的對象,那說明你濫用或者用錯了對象,mvc基本都是入?yún)?,返回,每一個請求都是一個線程,一個單獨(dú)的request response 有他們進(jìn)出的東西,完全是隔離的。由此說到mybatis,許多人用mybatis一個配置里面各種resmapper,每次都是各種bean來回走,一個請求下來,作為參數(shù)以及結(jié)果的bean必須有一次,mybatis表面上面清晰了sql維護(hù),是以極大程度拉低jdbc的效率為代價的,然后并沒有很多人在意,bean對他們來講,沒有什么,不了解也不關(guān)心gc,出來問題就加內(nèi)存,內(nèi)存加到頂,解決的只是時間問題,以空間換取時間。同樣的參數(shù)與結(jié)果映射,那么自己new 一個bean 使用jdk的map,哪個好,自然是jdk自身的map,
個人從來固執(zhí)的認(rèn)為,new一個jdk自身的對象,其消耗遠(yuǎn)小于自己定義一個bean。為什么,Sorry,i do not know either。所以我從來都是map來,map走。使用mybatis,一定要緊密檢測,你的事物代理到你的類上面了嗎,方法很簡單,在項(xiàng)目的log里面,打開debug,看你的日志是不是每次都是 create a new sqlsession,要是這樣的話 就要注意了 你的mybatis的session沒有池化,沒有被事物代理,一個方法里面如果出現(xiàn)了競爭性的sql,sorry 沒有任何錯誤,只是發(fā)現(xiàn)數(shù)據(jù)庫沒有執(zhí)行你的sql。很快,會發(fā)現(xiàn)連接池用的很快,頻繁的會創(chuàng)建新的connection。當(dāng)然如果可以不用mybatis,別猶豫,不用是對的。
為什么一定要盡量使用靜態(tài)注解呢,很簡單,spring的類基本都是singleton,項(xiàng)目夠大,bean實(shí)例也就夠多,這些單例的東西,占用了什么呢。對象實(shí)例在堆空間,引用在棧里面。那么gc什么時候會回收這些單例的對象呢?你認(rèn)為呢?所以,在基于注解的時候,盡量減少動態(tài)代理的使用。留更多的資源給需要用的地方用。
以前我們會說無堆不可無棧,現(xiàn)在要變了jdk1.7的string常量池已經(jīng)到堆里面了。
編譯型與解釋性哪個更好,當(dāng)然是解析式的,編譯型的類似于中介模型。因此構(gòu)建一門優(yōu)秀的編譯型語言,難度遠(yuǎn)大于解釋性語言。
web的結(jié)構(gòu)很清晰,首先依舊是上下文,然后是按照順序的一系列組件,我們最關(guān)鍵的是servlet組件,這個是javaee的標(biāo)準(zhǔn),其余的web組件是協(xié)議標(biāo)準(zhǔn),誰都必要有。那么會看見許多項(xiàng)目的servlet的mapping是/,這個是糟糕的方式,因?yàn)楹芎唵危琷s或者css從來沒有必要通過servlet來處理,因此mapping主要考慮到與web容器的服務(wù)端組件交互,一般給兩種標(biāo)識,比如.do and .action .do需要權(quán)限認(rèn)證之類,action屬于直接放行。js等不需要進(jìn)入servlet,由web上下文根據(jù)url直接去返回,然后就沒有在mvc里面加一個mvc的攔截與放行,多此一舉,制造問題,解決問題,不是好方式。這樣不管有沒有nginx的介入,你的靜態(tài)資源對于web容器來說就是靜態(tài)走的,沒有跟servlet產(chǎn)生關(guān)系。servlet只關(guān)系你需要其處理的東西。
js寫在哪里好?
很多人習(xí)慣把js寫在jsp里面或者h(yuǎn)tml里面,這樣說糟糕的。
我們構(gòu)建項(xiàng)目,必須希望我們的js與css是一定能夠被瀏覽器緩存的。
那么寫在頁面的script標(biāo)簽里面js,就是個標(biāo)簽而已,跟div或者input沒有區(qū)別,不會被緩存,我查閱很多資料,看見的緩存,明顯的寫著,緩存的單位是文件。而不是標(biāo)簽。所以把你的css js寫在文件里面,引入文件進(jìn)來,這樣文件會被緩存,這一點(diǎn),我并不完全確定,因?yàn)闆]有直接肯定的答案,是我的猜想。
jsp實(shí)際上servlet,因此是動態(tài)的頁面,每次都是需要加載class去動態(tài)翻譯,然后class里面的write方法將頁面寫到http給瀏覽器,瀏覽器渲染,如果是html,那么是靜態(tài)的。動態(tài)靈活,這個是毋庸置疑的,既然是servlet,那么就是java對象,各種Java的標(biāo)簽與方法稱為可能。靜態(tài)需要你自己去處理,靜態(tài)頁面使用類似宏語言,不如直接用jsp。
頁面上面,一次加載多少數(shù)據(jù)好?
如果你的頁面展示的東西按照類別,按照列表,數(shù)據(jù)量很少,幾百條,類型現(xiàn)在外賣點(diǎn)餐app的展示方式,那么,一次給出所有的分類跟數(shù)據(jù),所以的處理在客戶端處理,整個過程中的類別切換,預(yù)覽,全部在頁面去處理,包括搜索,我們客戶端的js, A的手機(jī)或者電腦里面執(zhí)行的js不會跟B的手機(jī)或者電腦產(chǎn)生競爭吧,如果每次切換一個類型就去刷一個ajax,都是同一個web容器群,這樣才有競爭。操作越頻繁,競爭越大。這點(diǎn)要緊密關(guān)系到實(shí)際的場景。
一次查詢返回的數(shù)據(jù)的量的多少與性能并無很多關(guān)系,幾千幾萬條數(shù)據(jù)不過幾十KB級別。
查詢的次數(shù),也就是交互到服務(wù)端的次數(shù)是影響整體性能的直接原因。
一次查詢的數(shù)據(jù)量多少與被查詢的表的大小是正比例,不會因?yàn)橐淮畏祷?0條加快查詢,一次返回1W條,拖慢查詢,數(shù)據(jù)庫操作本質(zhì)上就是集合應(yīng)用,并沒有創(chuàng)建什么。
調(diào)優(yōu)的前提是給多少最合適,不是給的越多越合適,jdk或者tomcat在不同位數(shù)不同的os上面能夠消耗的內(nèi)存都是有上限的。
使用nginx;
必要的時候使用緩存;
根據(jù)是否需要選擇消息中間件或者其他中間件;
數(shù)據(jù)庫的分離或者主從等,一定是當(dāng)前數(shù)據(jù)庫實(shí)在不能支撐業(yè)務(wù)量了。
單例是好的方式。
多線程是利刃,不區(qū)分具體哪種語言。
maven管理是好的方式,但是你的項(xiàng)目主體應(yīng)該是webmvc,建立web的項(xiàng)目,嵌入maven作為組件使用,而不是建立一個maven工程,再去轉(zhuǎn)成web項(xiàng)目,除非是閑的。
使用spring,目前是最好的腳手架。
盡可能使用jdbc,能夠做到的話。
能夠在客戶端完成的事情,就不要去交互到服務(wù)端,客戶端的資源是廣袤的,服務(wù)端的資源的有限的。
盡量少發(fā)請求,少發(fā)請求的代碼是好代碼,除非是你是即時的應(yīng)用。
每個代碼里面的工具都是工具,API是你最需要理解的,哪個好,哪個不好,沒有準(zhǔn)確答案。
一切皆對象,對于Java來講是純粹的,代理是對象,反射是對象,對象是對象,基本數(shù)據(jù)類型不是對象。
除了基本類型之外的東西,都是通過對象來完成,不管多復(fù)雜的流程,都是通過對應(yīng)的對象的方法結(jié)合方法的參數(shù)去完成的。一個class怎么序列化,怎么反序列化,說白了就是文件的io與傳輸,然后加載到j(luò)vm,構(gòu)造成對象。
rpc之所以rpc,調(diào)用的不是一個線程里面的東西,調(diào)用的東西,被代理了,代理把你的需求轉(zhuǎn)成參數(shù)作為數(shù)據(jù)流發(fā)出去了,服務(wù)端,把你的請求流再轉(zhuǎn)成對象,再流化發(fā)回去,你再構(gòu)造對象,通過對象來處理。
NIO是好的方式,netty是不錯的選擇,多線程的socket有超越netty的嗎?
zookeeper是好的分布式注冊等一系列方案的優(yōu)秀工具。
這些東西都是原理加對象,用就要去使勁看。
以上是個人理解,歡迎指正。
相關(guān)文章
Java項(xiàng)目實(shí)現(xiàn)模擬ATM機(jī)
這篇文章主要為大家詳細(xì)介紹了Java項(xiàng)目實(shí)現(xiàn)模擬ATM機(jī),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05解決java啟動時報線程占用報錯:Exception?in?thread?“Thread-14“?java.ne
這篇文章主要給大家介紹了關(guān)于解決java啟動時報線程占用:Exception?in?thread?“Thread-14“?java.net.BindException:?Address?already?in?use:?bind的相關(guān)資料,文中將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn)
這篇文章主要介紹了Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11SpringBoot使用H2嵌入式數(shù)據(jù)庫的實(shí)例代碼
本文通過實(shí)例代碼給大家介紹了SpringBoot使用H2嵌入式數(shù)據(jù)庫的相關(guān)知識,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-10-10關(guān)于Mybatis-Plus?Wrapper是否應(yīng)該出現(xiàn)在Servcie類中
最近在做代碼重構(gòu),代碼工程采用了Controller/Service/Dao分層架構(gòu),Dao層使用了Mybatis-Plus框架,本文帶領(lǐng)大家學(xué)習(xí)Mybatis-Plus?Wrapper應(yīng)該出現(xiàn)在Servcie類中嗎,需要的朋友可以參考下2023-05-05SpringBoot 入門教程之引入數(shù)據(jù)傳輸層的方法
這篇文章主要介紹了SpringBoot 入門教程之引入數(shù)據(jù)傳輸層的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07