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