綜述
- JDK版本:JDK8/JDK7 + OracleJDK/OpenJDK
- Java開發框架:Spring Boot/Spring + Hibernate/MyBatis
- 前后端分離:單頁應用/模板引擎
- 前后端接口文檔自動生成:Swagger
- 業務端邏輯校驗框架:Functional Validator/Fluent Validator/Hibernate Validator
- CT框架:Rundeck
- UT框架:TestNG/JUnit
- 歷史操作記錄方案:Canal/AOP/硬編碼
1. JDK版本
1.1 Why JDK8?
- 開發效率的提升:用更少的代碼完成更多的工作(Lambda代替匿名內部類、易於並行)
- 可以使用函數式思維編程(高階函數解放思想、消除副作用、簡潔、各語言發展的趨勢)
- 未來趨勢:一些開源項目及框架開始基於java8開發
- JVM新特性:元空間代替永久代(避免JDK以及前期版本中常見的永久內存錯誤OOM:PermGen)
1.1.1 JDK8與JDK7代碼對比
|
JDK7
|
JDK8
|
|---|---|
| for (int i = 0; i < arr.length; i++) { if (arr[i] % 2 != 0) { arr[i]++; } System.out.println(arr[i]); } |
Stream.of(arr) .map(x →(x % 2 == 0 ? x : x + 1)) .forEach(System.out::println); |
Optional:優雅的處理null
|
JDK7
|
JDK8
|
|---|---|
| public User getUser() { return user; } public List<Order> getOrders() { User user = getUser(); if (user != null) { return user.getOrders(); } else { return Collections.emptyList(); } } |
public Optional<User> getUser() { return Optional.ofNullable(user); } public List<Order> getOrders() { return getUser().map(u → u.getOrdes()) .orElse(Collections.emptyList()); } |
建議:如果接口的返回值有可能是null,請用Optional封裝
- 優雅,下游不用寫惡心的if-else判斷
- 安全:告知接口的使用方返回值可能為null,需要處理,以避免代碼缺陷
- 文檔化:接口中可能為空的值文檔化
1.1.2 易於並行
統計1-1000000內所有質數的數量
|
串行
|
並行
|
|---|---|
| IntStream.range(1, 1000000) .filter(PrimeUtil::isPrime) .count(); |
IntStream.range(1, 1000000) .parallel() .filter(PrimeUtil::isPrime) .count(); |
增強的Future:CompletableFuture
讀寫鎖的改進:StampedLock(樂觀的讀策略增加系統的並行度)
原子類的增強:LongAdder(更快的原子類)、LongAccumulator
1.1.3 JVM新特性:元空間代替永久代
參考:
http://www.infoq.com/cn/articles/Java-PERMGEN-Removed?from=groupmessage&isappinstalled=0
http://www.6gdown.com/softedupage/59348.html
- JDK7:“永久的”數據存放在一個叫做永久代的區域。永久代一段連續的內存空間,我們在JVM啟動之前可以通過設置-XX:MaxPermSize的值來控制永久代的大小,32位機器默認的永久代的大小為64M,64位的機器則為85M。永久代的垃圾回收和老年代的垃圾回收是綁定的,一旦其中一個區域被占滿,這兩個區都要進行垃圾回收。但是有一個明顯的問題,由於我們可以通過‑XX:MaxPermSize 設置永久代的大小,一旦類的元數據超過了設定的大小,程序就會耗盡內存,並出現內存溢出錯誤(OOM)。
- JDK8:“永久的”數據被移到了一個與堆不相連的本地內存區域(元空間),這項改動是很有必要的,因為對永久代進行調優是很困難的。永久代中的元數據可能會隨着每一次Full GC發生而進行移動。並且為永久代設置空間大小也是很難確定的,因為這其中有很多影響因素,比如類的總數,常量池的大小和方法數量等。將元數據從永久代剝離出來,不僅實現了對元空間的無縫管理,還可以簡化Full GC以及對以后的並發隔離類元數據等方面進行優化。
移除永久代的影響:
- 由於類的元數據分配在本地內存中,元空間的最大可分配空間就是系統可用內存空間。因此,我們就不會遇到永久代存在時的內存溢出錯誤,也不會出現泄漏的數據移到交換區這樣的事情。最終用戶可以為元空間設置一個可用空間最大值,如果不進行設置,JVM會自動根據類的元數據大小動態增加元空間的容量。
- 注意:永久代的移除並不代表自定義的類加載器泄露問題就解決了。因此,你還必須監控你的內存消耗情況,因為一旦發生泄漏,會占用你的大量本地內存,並且還可能導致交換區交換更加糟糕。
元空間數據管理:
- 元空間的內存管理由元空間虛擬機來完成。先前,對於類的元數據我們需要不同的垃圾回收器進行處理,現在只需要執行元空間虛擬機的C++代碼即可完成。在元空間中,類和其元數據的生命周期和其對應的類加載器是相同的。話句話說,只要類加載器存活,其加載的類的元數據也是存活的,因而不會被回收掉。
元空間調優:
- 默認情況下,-XX:MaxMetaspaceSize的值沒有限制,因此元空間甚至可以延伸到交換區,但是這時候當我們進行本地內存分配時將會失敗。
- 為了避免頻繁的GC,建議將–XX:MetaspaceSize設置為一個相對較高的值。對於一個64位的服務器端JVM來說,其默認的–XX:MetaspaceSize值為21MB。這就是初始的高水位線。一旦觸及到這個水位線,Full GC將會被觸發並卸載沒有用的類(即這些類對應的類加載器不再存活),然后這個高水位線將會重置。新的高水位線的值取決於GC后釋放了多少元空間。如果釋放的空間不足,這個高水位線則上升。如果釋放空間過多,則高水位線下降。如果初始化的高水位線設置過低,上述高水位線調整情況會發生很多次。
- 經過多次GC之后,元空間虛擬機自動調節高水位線,以此來推遲下一次垃圾回收到來。
- 有這樣兩個選項 ‑XX:MinMetaspaceFreeRatio和‑XX:MaxMetaspaceFreeRatio,他們類似於GC的FreeRatio選項,用來設置元空間空閑比例的最大值和最小值。我們可以通過命令行對這兩個選項設置對應的值。
獲取元空間信息的工具:
- jmap -clstats PID:打印類加載器數據(-clstats是-permstat的替代方案)
- jstat -gc LVMID:打印元空間的信息
- jcmd PID GC.class_stats:連接到運行的JVM並輸出詳盡的類元數據的柱狀圖。
存在的問題:元空間虛擬機采用了組塊分配的形式,同時區塊的大小由類加載器類型決定。類信息並不是固定大小,因此有可能分配的空閑區塊和類需要的區塊大小不同,這種情況下可能導致碎片存在。元空間虛擬機目前並不支持壓縮操作,所以碎片化是目前最大的問題。
1.1.4 關於垃圾收集
參考:http://developer.51cto.com/art/201508/489420.htm
1.2 OracleJDK和OpenJDK
穩妥起見,建議OracleJDK。
2. Java開發框架
2.1 Why Springboot?
參考《JavaEE開發的顛覆者:Spring Boot實戰》
理念:“習慣優於配置”(項目中存在大量的配置,此外還內置一個習慣性的配置,讓你無須手動進行配置),讓項目快速運行起來。使用Spring Boot很容易創建一個獨立運行(運行jar,內嵌Servlet容器)、准生產級別的基於Spring框架的項目,使用spring Boot你可以不用或者只需要很少的Spring配置。
核心功能:
- 獨立運行的Spring項目:Spring Boot可以以jar包的形式獨立運行,運行一個Spring Boot項目只需要通過java -jar xx.jar來運行。
- 內嵌Servlet容器:Spring Boot可選擇內嵌Tomcat、Jetty或者Undertow,這樣我們無須以war包形式部署項目。
- 提供starter簡化Maven配置:如使用了spring-boot-starter-web時,會自動加入相關依賴包。
- 自動配置Spring:Spring Boot會根據在類路徑中的jar包、類,為jar包里的類自動配置Bean。
- 准生產的應用監控:提供基於http、ssh、telnet對運行時的項目進行監控。
- 無代碼生成和xml配置:條件注解而不是xml配置。
優點:
- 快速構建項目
- 對主流開發框架的無配置集成
- 項目可獨立運行,無須外部依賴Servlet容器
- 提供運行時的應用監控
- 極大地提高了開發、部署效率
- 與雲計算的天然集成
缺點:
- 書籍文檔較少且不夠深入
2.2 Hibernate和MyBatis
參考http://blog.csdn.net/firejuly/article/details/8190229
MyBatis優勢:
- MyBatis可以進行更為細致的SQL優化,可以減少查詢字段。
- MyBatis容易掌握,而Hibernate門檻較高。
Hibernate優勢:
- Hibernate的DAO層開發比MyBatis簡單,Mybatis需要維護SQL和結果映射。
- Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便。
- Hibernate數據庫移植性很好,MyBatis的數據庫移植性不好,不同的數據庫需要寫不同SQL。
- Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。
3. 前后端分離:單頁應用 OR 模板引擎
4. 前后端接口文檔自動生成:Swagger
參考:http://blog.csdn.net/wangnan9279/article/details/44541665
Swagger 是一款RESTFUL接口的文檔在線自動生成+功能測試功能軟件。是一個規范和完整的框架,用於生成、描述、調用和可視化 RESTful 風格的 Web 服務。總體目標是使客戶端和文件系統作為服務器以同樣的速度來更新。文件的方法,參數和模型緊密集成到服務器端的代碼,允許API來始終保持同步。
5. 業務端校驗框架
FunctionalValidator介紹:http://jiebaojie.com/2017/01/28/FunctionalValidator/
主要優點:
- 校驗邏輯與業務邏輯解耦(HibernateValidator只能解決單參數的校驗)
- 目標提供更優雅、更易用的函數式業務邏輯驗證框架(相比FluentValidator的優勢)
缺點:
- 不支持JDK7及以下版本
- 需要對java8語法及函數式編程思想有一定了解
6. CT框架:Rundeck
參考:http://www.tuicool.com/articles/22me6zA
rundeck是一款開源的可以幫助你在數據中心或者雲環境自動運行日常程序的軟件,rundeck提供了一些特性來緩解費事繁瑣的工作,並且很容易讓你擴展自己的自動化成果。rundeck允許你在web界面或者命令行上指定在任何節點運行任務。rundeck也包含了其他特性來容易的擴展的你的自動化成果,例如:訪問控制、工作流構建、調度、日志等等。
特性:
- 提供web api
- 分布式命令執行
- 可插拔的系統插件
- 多步驟工作流構建
- 以守護進程執行job或者調度運行
- 圖形化web控制台來控制job執行
- 基於規則的訪問控制,支持LDAP/AD
- 歷史及構建日志查看
- 可以集成到外部工具
- 命令行控制工具
7. UT框架:TestNG和JUnit
參考:http://www.mkyong.com/unittest/junit-4-vs-testng-comparison/
中文翻譯版:http://www.importnew.com/16270.html
TestNG 在參數化測試、依賴測試以及套件測試(組)方面功能更加強大。TestNG 意味着高級的測試和復雜的集成測試。它更加的靈活,特別是對大的套件測試。
8. 歷史操作記錄方案
9. MOCK框架
Mockito和JMockit。
兩者的區別是,前者不能mock static method和final class、final method,后者可以,本項目mockito足以。




