Java開發坑點解析:從根因分析到最佳實踐
朱曄
買這商品的人也買了...
-
$420$332 -
$390$332 -
$580$458 -
$714$678 -
$403程序員的三門課:技術精進、架構修煉、管理探秘
-
$580$458 -
$505軟件測試 — 原理、模型、驗證與實踐
-
$780$616 -
$828$787 -
$658深入理解高並發編程:核心原理與案例實戰
-
$505持續架構實踐:敏捷和 DevOps 時代下的軟件架構
-
$474$450 -
$534$507 -
$580$458 -
$680$537 -
$588$559 -
$620$484 -
$654$621 -
$479$455 -
$779$740 -
$490$387 -
$599$569 -
$839$797 -
$510Redis 高手心法
-
$850$672
相關主題
商品描述
本書從整個Java後端研發的視角,通過大量的案例分析日常開發過程中可能遇到的150多個坑點及其解決方案,並討論一些best實踐。這些坑點涵蓋編碼(不僅涉及Java語法層面,還涉及多線程、連接池、數據庫索引、事務、日誌、Spring框架等層面)、系統設計、代碼安全等方面。本書在剖析這些坑點時還會講解排查思路和相關工具的使用,讓讀者不僅能瞭解常見的坑點,還能具備一定的問題分析能力,以便日後自行排查更多的坑點。
作者簡介
朱晔,晖致医药架构师,从事互联网行业(教育、游戏、电商、O2O、P2P等领域)研发和架构设计工作超过15年,曾任职于育碧软件、英孚教育、空中网、饿了么、贝壳等公司,熟悉微服务架构,擅长高并发、高可用架构。从业以来一直没有脱离编码工作,参与过400多个应用的架构设计和开发,并且经常作为“救火队员”在一线排查和分析各种故障,具备丰富的问题排查经验,对如何设计健壮和安全的业务系统也有着深刻的理解。
目錄大綱
第 1章 Java 8中常用的重要知識點 1
1.1 在項目中使用Lambda表達式和流操作 1
1.2 Lambda表達式 2
1.3 使用Java 8簡化代碼 4
1.3.1 使用流操作簡化集合操作 4
1.3.2 使用可空類型簡化判空邏輯 5
1.3.3 使用Java 8的一些新類、新方法獲得函數式編程體驗 6
1.4 並行流 8
1.5 流操作詳解 11
1.5.1 創建流 12
1.5.2 filter 14
1.5.3 map 14
1.5.4 flatMap 14
1.5.5 sorted 15
1.5.6 distinct 15
1.5.7 skip和limit 15
1.5.8 collect 16
1.5.9 groupingBy 17
1.5.10 partitioningBy 19
1.6 小結 19
1.7 思考與討論 19
第 2章 代碼篇 23
2.1 使用了並發工具類庫,並不等於就沒有線程安全問題了 23
2.1.1 沒有意識到線程重用導致用戶信息錯亂的bug 23
2.1.2 使用了線程安全的並發工具,並不代表解決了所有線程安全問題 25
2.1.3 沒有充分瞭解並發工具的特性,從而無法發揮其威力 28
2.1.4 沒有認清並發工具的使用場景,因而導致性能問題 30
2.1.5 小結 32
2.1.6 思考與討論 32
2.2 代碼加鎖:不要讓鎖成為煩心事 33
2.2.1 加鎖前要清楚鎖和被保護的對象是不是一個層面的 35
2.2.2 加鎖要考慮鎖的粒度和場景問題 36
2.2.3 多把鎖要小心死鎖問題 37
2.2.4 小結 40
2.2.5 思考與討論 40
2.3 線程池:業務代碼中最常用也最容易犯錯的組件 41
2.3.1 線程池的聲明需要手動進行 41
2.3.2 線程池線程管理策略詳解 43
2.3.3 務必確認清楚線程池本身是不是復用的 47
2.3.4 需要仔細斟酌線程池的混用策略 48
2.3.5 小結 51
2.3.6 思考與討論 51
2.3.7 擴展閱讀 52
2.4 連接池:別讓連接池幫了倒忙 54
2.4.1 註意鑒別客戶端SDK是否基於連接池 55
2.4.2 使用連接池務必確保復用 60
2.4.3 連接池的配置不是一成不變的 64
2.4.4 小結 67
2.4.5 思考與討論 67
2.5 HTTP調用:你考慮超時、重試、並發了嗎 68
2.5.1 配置連接超時和讀取超時參數的學問 69
2.5.2 Feign和Ribbon配合使用,你知道怎麽配置超時嗎 70
2.5.3 你知道Ribbon會自動重試請求嗎 73
2.5.4 並發限制了爬蟲的抓取能力 75
2.5.5 小結 77
2.5.6 思考與討論 78
2.5.7 擴展閱讀 78
2.6 20%的業務代碼的Spring聲明式事務可能都沒處理正確 80
2.6.1 小心Spring的事務可能沒有生效 80
2.6.2 事務即便生效也不一定能回滾 84
2.6.3 請確認事務傳播配置是否符合自己的業務邏輯 86
2.6.4 小結 89
2.6.5 思考與討論 90
2.6.6 擴展閱讀 93
2.7 數據庫索引:索引不是萬能藥 94
2.7.1 InnoDB是如何存儲數據的 95
2.7.2 聚簇索引和二級索引 96
2.7.3 考慮額外創建二級索引的代價 97
2.7.4 不是所有針對索引列的查詢都能用上索引 99
2.7.5 數據庫基於成本決定是否走索引 101
2.7.6 小結 104
2.7.7 思考與討論 104
2.8 判等問題:程序里如何確定你就是你 105
2.8.1 註意equals和==的區別 106
2.8.2 實現一個equals沒有這麽簡單 110
2.8.3 hashCode和equals要配對實現 112
2.8.4 註意compareTo和equals的邏輯一致性 114
2.8.5 小心Lombok生成代碼的坑 115
2.8.6 小結 117
2.8.7 思考與討論 117
2.8.8 擴展閱讀 118
2.9 數值計算:註意精度、舍入和溢出問題 119
2.9.1 “危險”的Double 120
2.9.2 考慮浮點數舍入和格式化的方式 121
2.9.3 用equals做判等,就一定是對的嗎 122
2.9.4 小心數值溢出問題 123
2.9.5 小結 125
2.9.6 思考與討論 125
2.9.7 擴展閱讀 126
2.10 集合類:坑滿地的List列表操作 127
2.10.1 使用Arrays.asList把數據轉換為List的3個坑 127
2.10.2 使用List.subList進行切片操作居然會導致OOM 129
2.10.3 一定要讓合適的數據結構做合適的事情 132
2.10.4 小結 136
2.10.5 思考與討論 137
2.11 空值處理:分不清楚的null和惱人的空指針 138
2.11.1 修復和定位惱人的空指針問題 138
2.11.2 POJO中屬性的null到底代表了什麽 142
2.11.3 小心MySQL中有關NULL的3個坑 146
2.11.4 小結 147
2.11.5 思考與討論 147
2.12 異常處理:別讓自己在出問題的時候變為盲人 149
2.12.1 捕獲和處理異常容易犯的錯 149
2.12.2 小心finally中的異常 153
2.12.3 需要註意JVM針對異常性能優化導致棧信息丟失的坑 155
2.12.4 千萬別把異常定義為靜態變量 157
2.12.5 提交線程池的任務出了異常會怎樣 158
2.12.6 小結 161
2.12.7 思考與討論 162
2.12.8 擴展閱讀 163
2.13 日誌:日誌記錄真沒你想象得那麽簡單 164
2.13.1 為什麽我的日誌會重復記錄 165
2.13.2 使用異步日誌改善性能的坑 169
2.13.3 使用日誌占位符就不需要進行日誌級別判斷了嗎 175
2.13.4 小結 176
2.13.5 思考與討論 176
2.13.6 擴展閱讀 178
2.14 文件I/O:實現高效正確的文件讀寫並非易事 180
2.14.1 文件讀寫需要確保字符編碼一致 180
2.14.2 使用Files類靜態方法進行文件操作註意釋放文件句柄 182
2.14.3 註意讀寫文件要考慮設置緩沖區 184
2.14.4 小結 187
2.14.5 思考與討論 187
2.14.6 擴展閱讀 188
2.15 序列化:一來一回,你還是原來的你嗎 190
2.15.1 序列化和反序列化需要確保算法一致 191
2.15.2 MyBatisPlus讀取泛型List
2.15.3 註意Jackson JSON反序列化對額外字段的處理 198
2.15.4 反序列化時要小心類的構造方法 200
2.15.5 枚舉作為API接口參數或返回值的兩個大坑 201
2.15.6 小結 207
2.15.7 思考與討論 207
2.16 用好Java 8的日期時間類,少踩一些“老三樣”的坑 208
2.16.1 初始化日期時間 209
2.16.2 “惱人”的時區問題 209
2.16.3 日期時間格式化和解析 212
2.16.4 日期時間的計算 215
2.16.5 小結 217
2.16.6 思考與討論 218
2.16.7 擴展閱讀 219
2.17 別以為“自動擋”就不可能出現OOM 220
2.17.1 太多份相同的對象導致OOM 220
2.17.2 使用WeakHashMap不等於不會OOM 223
2.17.3 Tomcat參數配置不合理導致OOM 227
2.17.4 小結 228
2.17.5 思考與討論 229
2.17.6 擴展閱讀 230
2.18 當反射、註解和泛型遇到OOP時,會有哪些坑 231
2.18.1 反射調用方法不是以傳參決定重載 231
2.18.2 泛型經過類型擦除多出橋接方法的坑 232
2.18.3 註解可以繼承嗎 237
2.18.4 小結 239
2.18.5 思考與討論 239
2.18.6 擴展閱讀 241
2.19 Spring框架:IoC和AOP是擴展的核心 243
2.19.1 單例的Bean如何註入Prototype的Bean 244
2.19.2 監控切麵因為順序問題導致Spring事務失效 247
2.19.3 小結 255
2.19.4 思考與討論 255
2.19.5 知識擴展:同樣註意枚舉是單例的問題 256
2.20 Spring框架:幫我們做了很多工作也帶來了復雜度 258
2.20.1 Feign AOP切不到的詭異案例 258
2.20.2 Spring程序配置的優先級問題 264
2.20.3 小結 273
2.20.4 思考與討論 273
2.20.5 擴展閱讀 275
第3章 系統設計 281
3.1 代碼重復:搞定代碼重復的3個絕招 281
3.1.1 利用“工廠模式+模板方法模式”,消除if...else...和重復代碼 281
3.1.2 利用“註解+反射”消除重復代碼 287
3.1.3 利用屬性拷貝工具消除重復代碼 291
3.1.4 小結 293
3.1.5 思考與討論 293
3.2 接口設計:系統間對話的語言,一定要統一 294
3.2.1 接口的響應要明確表示接口的處理結果 294
3.2.2 要考慮接口變遷的版本控制策略 300
3.2.3 接口處理方式要明確同步還是異步 302
3.2.4 小結 305
3.2.5 思考與討論 305
3.2.6 擴展閱讀 307
3.3 緩存設計:緩存可以錦上添花也可以落井下石 307
3.3.1 不要把Redis當作數據庫 308
3.3.2 註意緩存雪崩問題 309
3.3.3 註意緩存擊穿問題 312
3.3.4 註意緩存穿透問題 314
3.3.5 註意緩存數據同步策略 316
3.3.6 小結 317
3.3.7 思考與討論 317
3.3.8 擴展閱讀 318
3.4 業務代碼寫完,就意味著生產就緒了嗎 320
3.4.1 準備工作:配置Spring Boot Actuator 321
3.4.2 健康監測需要觸達關鍵組件 322
3.4.3 對外暴露應用內部重要組件的狀態 327
3.4.4 指標是快速定位問題的“金鑰匙” 330
3.4.5 小結 339
3.4.6 思考與討論 339
3.5 異步處理好用,但非常容易用錯 342
3.5.1 異步處理需要消息補償閉環 342
3.5.2 註意消息模式是廣播還是工作隊列 346
3.5.3 別讓死信堵塞了消息隊列 351
3.5.4 小結 355
3.5.5 思考與討論 356
3.6 數據存儲:NoSQL與RDBMS如何取長補短、相輔相成 358
3.6.1 取長補短之Redis vs MySQL 358
3.6.2 取長補短之InfluxDB vs MySQL 361
3.6.3 取長補短之Elasticsearch vs MySQL 364
3.6.4 結合NoSQL和MySQL應對高並發的復合數據庫架構 369
3.6.5 小結 371
3.6.6 思考與討論 371
第4章 代碼安全問題 373
4.1 數據源頭:任何客戶端的東西都不可信任 373
4.1.1 客戶端的計算不可信 373
4.1.2 客戶端提交的參數需要校驗 375
4.1.3 不能信任請求頭里的任何內容 377
4.1.4 用戶標識不能從客戶端獲取 378
4.1.5 小結 380
4.1.6 思考與討論 380
4.2 安全兜底:涉及錢時,必須考慮防刷、限量和防重 381
4.2.1 開放平臺資源的使用需要考慮防刷 381
4.2.2 虛擬資產並不能憑空產生無限使用 382
4.2.3 錢的進出一定要和訂單掛鉤並且實現冪等 384
4.2.4 小結 386
4.2.5 思考與討論 386
4.2.6 擴展閱讀 386
4.3 數據和代碼:數據就是數據,代碼就是代碼 387
4.3.1 SQL註入能乾的事情比你想象得更多 388
4.3.2 小心動態執行代碼時代碼註入漏洞 393
4.3.3 XSS必須全方位嚴防死堵 396
4.3.4 小結 403
4.3.5 思考與討論 403
4.3.6 擴展閱讀 404
4.4 如何正確地保存和傳輸敏感數據 405
4.4.1 如何保存用戶密碼 406
4.4.2 如何保存姓名和身份證號碼 409
4.4.3 用一張圖說清楚HTTPS 416
4.4.4 小結 418
4.4.5 思考與討論 419
第5章 Java程序故障排查 420
5.1 定位Java應用問題的排錯套路 420
5.1.1 生產問題的排查很大程度依賴監控 420
5.1.2 分析定位問題的套路 421
5.1.3 分析和定位問題需要註意的9個點 422
5.1.4 小結 424
5.1.5 思考與討論 424
5.2 分析定位Java問題,一定要用好這些工具 425
5.2.1 使用JDK自帶工具查看JVM情況 425
5.2.2 使用Wireshark分析SQL批量插入慢的問題 433
5.2.3 使用MAT分析OOM問題 438
5.2.4 使用Arthas分析高CPU問題 444
5.2.5 小結 448
5.2.6 思考與討論 449
5.3 Java程序從虛擬機遷移到Kubernetes的一些坑 452
5.3.1 Pod IP不固定帶來的坑 452
5.3.2 程序因為OOM被殺進程的坑 453
5.3.3 內存和CPU資源配置不適配容器的坑 454
5.3.4 Pod重啟以及重啟後沒有現場的坑 455
5.3.5 小結 455
5.3.6 思考與討論 456
後記:寫代碼時,如何才能盡量避免踩坑 457