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