JAVAEE專案結構以及併發隨想

farsun發表於2021-09-09

摘要:
長久以來統領javaee領域的腳手架以spring struts2 mybatis/hibernate引領;

Spring:

Spring is not just for Java services。spring作為cgi標準的實現,並不僅僅是作為Java領域的框架,C#平臺依舊可以獲益;spring提供了抽象化等各種方便的註解配置方式或者bootde 一體化方案,極大簡化了Javaee的專案基礎;

在spring的使用過程中,兩面分化,一部分,輕量註解,一部分傾向於全註解。

首先註解的前提是必然要經歷代理的,動態,靜態,cglib代理。對於輕量註解,角度站在靜態或者說是一次性註解,

比如controller註解,這些一次性的註解或者是編譯期的註解,在專案上下文初始化作為一個隱射一次性掃描,相關的有service等類似註解,提供了單例的輕量級物件例項。視為首選。這樣減少了執行期的代理,反射,這些動輒大動干戈的消耗,也為執行期的堆疊節約了更好的資源。

另一類比如responsebody,這類屬於動態註解或者執行期的註解,每次請求,都會執行該註解的反射。執行期的註解,想當然是要佔用資源的。

總的來講,不是必須的註解完全可以不註解,基於servlet基礎的request,response方式沒有解決不了的mvc,取參,傳參,返回等,完全不需要執行期的註解,執行期的註解看似是減少了程式碼量,為了補住這過程的各種缺,會執行一個圓環的動態註解來執行一個被你用在方法內部的註解。對於寫在方法裡面的param註解,相比於自己用request get 究竟少了哪些程式碼?不過是讓原本一步到位的處理,加入了一層程式碼攔截。

如何知道一個註解是否是執行期或者編譯期的註解,很簡單,Ctrl+滑鼠點選,會看見:

@Target({ElementType.TYPE, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

Retention 這個列舉型別完整清晰的說明了你使用的註解的作用期。

用spring 大家都喜歡用單例,這是極好的方式,單例與併發本身毫無關係,除了你非要讓它產生資源標識競爭,

如果說你的專案中必須要出現許多prototype的物件,那說明你濫用或者用錯了物件,mvc基本都是入參,返回,每一個請求都是一個執行緒,一個單獨的request response 有他們進出的東西,完全是隔離的。由此說到mybatis,許多人用mybatis一個配置裡面各種resmapper,每次都是各種bean來回走,一個請求下來,作為引數以及結果的bean必須有一次,mybatis表面上面清晰了sql維護,是以極大程度拉低jdbc的效率為代價的,然後並沒有很多人在意,bean對他們來講,沒有什麼,不瞭解也不關心gc,出來問題就加記憶體,記憶體加到頂,解決的只是時間問題,以空間換取時間。同樣的引數與結果對映,那麼自己new 一個bean 使用jdk的map,哪個好,自然是jdk自身的map,

個人從來固執的認為,new一個jdk自身的物件,其消耗遠小於自己定義一個bean。為什麼,Sorry,i do not know either。所以我從來都是map來,map走。使用mybatis,一定要緊密檢測,你的事物代理到你的類上面了嗎,方法很簡單,在專案的log裡面,開啟debug,看你的日誌是不是每次都是 create a new sqlsession,要是這樣的話 就要注意了 你的mybatis的session沒有池化,沒有被事物代理,一個方法裡面如果出現了競爭性的sql,sorry 沒有任何錯誤,只是發現資料庫沒有執行你的sql。很快,會發現連線池用的很快,頻繁的會建立新的connection。當然如果可以不用mybatis,別猶豫,不用是對的。

為什麼一定要儘量使用靜態註解呢,很簡單,spring的類基本都是singleton,專案夠大,bean例項也就夠多,這些單例的東西,佔用了什麼呢。物件例項在堆空間,引用在棧裡面。那麼gc什麼時候會回收這些單例的物件呢?你認為呢?所以,在基於註解的時候,儘量減少動態代理的使用。留更多的資源給需要用的地方用。

以前我們會說無堆不可無棧,現在要變了jdk1.7的string常量池已經到堆裡面了。

編譯型與解釋性哪個更好,當然是解析式的,編譯型的類似於中介模型。因此構建一門優秀的編譯型語言,難度遠大於解釋性語言。

web的結構很清晰,首先依舊是上下文,然後是按照順序的一系列元件,我們最關鍵的是servlet元件,這個是javaee的標準,其餘的web元件是協議標準,誰都必要有。那麼會看見許多專案的servlet的mapping是/,這個是糟糕的方式,因為很簡單,js或者css從來沒有必要透過servlet來處理,因此mapping主要考慮到與web容器的服務端元件互動,一般給兩種標識,比如.do and .action .do需要許可權認證之類,action屬於直接放行。js等不需要進入servlet,由web上下文根據url直接去返回,然後就沒有在mvc裡面加一個mvc的攔截與放行,多此一舉,製造問題,解決問題,不是好方式。這樣不管有沒有nginx的介入,你的靜態資源對於web容器來說就是靜態走的,沒有跟servlet產生關係。servlet只關係你需要其處理的東西。

js寫在哪裡好?

很多人習慣把js寫在jsp裡面或者html裡面,這樣說糟糕的。

我們構建專案,必須希望我們的js與css是一定能夠被瀏覽器快取的。

那麼寫在頁面的script標籤裡面js,就是個標籤而已,跟div或者input沒有區別,不會被快取,我查閱很多資料,看見的快取,明顯的寫著,快取的單位是檔案。而不是標籤。所以把你的css js寫在檔案裡面,引入檔案進來,這樣檔案會被快取,這一點,我並不完全確定,因為沒有直接肯定的答案,是我的猜想。

jsp實際上servlet,因此是動態的頁面,每次都是需要載入class去動態翻譯,然後class裡面的write方法將頁面寫到http給瀏覽器,瀏覽器渲染,如果是html,那麼是靜態的。動態靈活,這個是毋庸置疑的,既然是servlet,那麼就是java物件,各種Java的標籤與方法稱為可能。靜態需要你自己去處理,靜態頁面使用類似宏語言,不如直接用jsp。

頁面上面,一次載入多少資料好?

如果你的頁面展示的東西按照類別,按照列表,資料量很少,幾百條,型別現在外賣點餐app的展示方式,那麼,一次給出所有的分類跟資料,所以的處理在客戶端處理,整個過程中的類別切換,預覽,全部在頁面去處理,包括搜尋,我們客戶端的js, A的手機或者電腦裡面執行的js不會跟B的手機或者電腦產生競爭吧,如果每次切換一個型別就去刷一個ajax,都是同一個web容器群,這樣才有競爭。操作越頻繁,競爭越大。這點要緊密關係到實際的場景。

一次查詢返回的資料的量的多少與效能並無很多關係,幾千幾萬條資料不過幾十KB級別。

查詢的次數,也就是互動到服務端的次數是影響整體效能的直接原因。

一次查詢的資料量多少與被查詢的表的大小是正比例,不會因為一次返回10條加快查詢,一次返回1W條,拖慢查詢,資料庫操作本質上就是集合應用,並沒有建立什麼。

調優的前提是給多少最合適,不是給的越多越合適,jdk或者tomcat在不同位數不同的os上面能夠消耗的記憶體都是有上限的。

使用nginx;

必要的時候使用快取;

根據是否需要選擇訊息中介軟體或者其他中介軟體;

資料庫的分離或者主從等,一定是當前資料庫實在不能支撐業務量了。

單例是好的方式。

多執行緒是利刃,不區分具體哪種語言。

maven管理是好的方式,但是你的專案主體應該是webmvc,建立web的專案,嵌入maven作為元件使用,而不是建立一個maven工程,再去轉成web專案,除非是閒的。

使用spring,目前是最好的腳手架。

儘可能使用jdbc,能夠做到的話。

能夠在客戶端完成的事情,就不要去互動到服務端,客戶端的資源是廣袤的,服務端的資源的有限的。

儘量少發請求,少發請求的程式碼是好程式碼,除非是你是即時的應用。

每個程式碼裡面的工具都是工具,API是你最需要理解的,哪個好,哪個不好,沒有準確答案。

一切皆物件,對於Java來講是純粹的,代理是物件,反射是物件,物件是物件,基本資料型別不是物件。

除了基本型別之外的東西,都是透過物件來完成,不管多複雜的流程,都是透過對應的物件的方法結合方法的引數去完成的。一個class怎麼序列化,怎麼反序列化,說白了就是檔案的io與傳輸,然後載入到jvm,構造成物件。

rpc之所以rpc,呼叫的不是一個執行緒裡面的東西,呼叫的東西,被代理了,代理把你的需求轉成引數作為資料流發出去了,服務端,把你的請求流再轉成物件,再流化發回去,你再構造物件,透過物件來處理。

NIO是好的方式,netty是不錯的選擇,多執行緒的socket有超越netty的嗎?

zookeeper是好的分散式註冊等一系列方案的優秀工具。

這些東西都是原理加物件,用就要去使勁看。

以上是個人理解,歡迎指正。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4289/viewspace-2798301/,如需轉載,請註明出處,否則將追究法律責任。

相關文章