盤:考點(diǎn)與復(fù)習(xí)思路)
最近不少學(xué)弟學(xué)妹來問我校招筆試題怎么準(zhǔn)備正好手頭翻出一份當(dāng)年整理過的“酷家樂2020校園招聘-后端A卷”的完整復(fù)盤筆記。酷家樂作為云設(shè)計(jì)SaaS賽道的頭部公司技術(shù)棧偏Java方向后端校招題的考察范圍很有代表性——既有基礎(chǔ)扎實(shí)度的試探又有工程化能力的驗(yàn)證非常適合用來對(duì)標(biāo)查漏補(bǔ)缺。這篇內(nèi)容我就順著這份試卷把每一類題背后的考點(diǎn)、踩坑點(diǎn)、以及對(duì)應(yīng)的復(fù)習(xí)思路一次說清楚。1. 試卷整體設(shè)計(jì)與人才篩選邏輯先說一個(gè)很多人容易忽略的點(diǎn)校招筆試題不是用來考倒你的而是用來給候選人畫像的??峒覙愤@套后端A卷整體風(fēng)格是“基礎(chǔ)題為主、場(chǎng)景題為輔、工程細(xì)節(jié)穿插其中”這與其實(shí)際業(yè)務(wù)強(qiáng)相關(guān)——云設(shè)計(jì)平臺(tái)的渲染任務(wù)調(diào)度、模型數(shù)據(jù)存儲(chǔ)、大規(guī)模并發(fā)訪問都要求后端工程師具備扎實(shí)的Java基礎(chǔ)、數(shù)據(jù)庫調(diào)優(yōu)意識(shí)和分布式系統(tǒng)常識(shí)。整套卷子的題型分布大致是四塊Java基礎(chǔ)與并發(fā)、數(shù)據(jù)庫與緩存、框架與工程化、系統(tǒng)設(shè)計(jì)場(chǎng)景題。前兩塊是“基本盤”答不好基本沒戲后兩塊是“分水嶺”決定你能不能進(jìn)入下一輪面試。不是說冷門知識(shí)點(diǎn)考得多深而是每個(gè)知識(shí)點(diǎn)都貼著真實(shí)業(yè)務(wù)場(chǎng)景出題這就要求你平時(shí)學(xué)技術(shù)不能只停留在“會(huì)用API”而是要去理解底層原理。另外值得注意的一點(diǎn)是這套卷子沒有太多偏題怪題沒有讓你默寫某個(gè)冷門注解的全限定名也沒有讓你手寫紅黑樹。它的核心訴求很清楚驗(yàn)證你有沒有形成一套完整的后端知識(shí)體系而不是靠死記硬背突擊出來的碎片記憶。1.1 校招筆試題的常見命題邏輯大部分公司的校招后端卷命題邏輯高度相似酷家樂A卷也不例外。總結(jié)下來就是三層遞進(jìn)第一層是語言基礎(chǔ)圍繞集合、并發(fā)、JVM、異常處理展開考察的是“你寫沒寫過足夠的代碼”。第二層是中間件與存儲(chǔ)圍繞MySQL索引與事務(wù)、Redis緩存與持久化、消息隊(duì)列的使用場(chǎng)景展開考察的是“你有沒有真正做過一個(gè)完整項(xiàng)目”。第三層是設(shè)計(jì)與工程化圍繞接口設(shè)計(jì)、冪等性、分布式鎖、容器部署來展開考察的是“你有沒有想過線上環(huán)境是什么樣子”。這三層不是并列關(guān)系而是遞進(jìn)關(guān)系。筆試題往往把三層內(nèi)容混在一起出目的就是篩掉那些只刷了第一層題庫就以為自己準(zhǔn)備好了的人。所以你在準(zhǔn)備時(shí)一定要按這個(gè)層次去搭建自己的知識(shí)樹而不是東一榔頭西一棒子地刷題。1.2 酷家樂后端崗位的技術(shù)畫像從這套A卷反推酷家樂后端團(tuán)隊(duì)的用人偏好能看出幾個(gè)明顯信號(hào)。首先是Java為主Spring生態(tài)是標(biāo)配因?yàn)樵嚲砝颯pring相關(guān)的內(nèi)容占比不小其次是重視存儲(chǔ)層能力MySQL和Redis幾乎是必考再次是關(guān)注并發(fā)場(chǎng)景這與酷家樂渲染集群的調(diào)度需求吻合。信號(hào)背后其實(shí)是一個(gè)很實(shí)在的問題這家公司希望你入職后能快速參與真實(shí)業(yè)務(wù)開發(fā)。而真實(shí)業(yè)務(wù)開發(fā)中Java基礎(chǔ)不牢會(huì)導(dǎo)致代碼質(zhì)量失控?cái)?shù)據(jù)庫設(shè)計(jì)不合理會(huì)導(dǎo)致線上事故緩存使用不當(dāng)會(huì)導(dǎo)致數(shù)據(jù)不一致。所以筆試題就是在提前模擬這些“事故現(xiàn)場(chǎng)”看你會(huì)不會(huì)踩坑、能不能給出合理方案。2. 核心題型逐一拆解與答題思路接下來說正題我把這份A卷里的代表性題目和對(duì)應(yīng)的知識(shí)點(diǎn)展開講。雖然每場(chǎng)考試的具體題目會(huì)變但考察的知識(shí)點(diǎn)是有規(guī)律可循的掌握了規(guī)律題目怎么變你都不慌。2.1 Java基礎(chǔ)與并發(fā)部分HashMap、線程池與JVMJava基礎(chǔ)這部分酷家樂A卷幾乎必考HashMap。這里我要特別提醒一句別停留在“HashMap允許null鍵、Hashtable不允許”這種背誦層面面試官和閱卷人真正想看的是你清不清楚擴(kuò)容機(jī)制和哈希沖突處理。我建議你至少要能說清楚這么幾條HashMap默認(rèn)容量是16負(fù)載因子是0.75當(dāng)元素個(gè)數(shù)超過容量 * 負(fù)載因子時(shí)觸發(fā)擴(kuò)容擴(kuò)容時(shí)新容量是原來的兩倍元素的位置要么不變要么在原位置基礎(chǔ)上偏移舊容量的長(zhǎng)度。這個(gè)“要么不變、要么偏移2的冪次方”的規(guī)律很多人知道是知道但說不出為什么——因?yàn)閿U(kuò)容時(shí)判斷(e.hash oldCap) 0來決定是否移動(dòng)這個(gè)位運(yùn)算技巧很巧妙說說清楚絕對(duì)加分。還有一個(gè)高概率考點(diǎn)是線程池。別只背Executors.newFixedThreadPool()這類工廠方法要從ThreadPoolExecutor的七大參數(shù)講起核心線程數(shù)、最大線程數(shù)、空閑存活時(shí)間、時(shí)間單位、阻塞隊(duì)列、線程工廠、拒絕策略。尤其要能根據(jù)自己的理解說明白為什么阿里規(guī)范不推薦使用Executors的快捷方法因?yàn)閚ewFixedThreadPool的隊(duì)列是無界LinkedBlockingQueue任務(wù)堆積過多會(huì)導(dǎo)致OOMnewCachedThreadPool的最大線程數(shù)是Integer.MAX_VALUE在高并發(fā)下會(huì)創(chuàng)建過多線程導(dǎo)致線程資源耗盡。JVM部分重點(diǎn)準(zhǔn)備兩類題一是內(nèi)存區(qū)域劃分堆、棧、方法區(qū)、程序計(jì)數(shù)器、本地方法棧每個(gè)區(qū)域存什么、會(huì)不會(huì)OOM二是GC垃圾回收新生代和老年代的回收算法差異、常見收集器如CMS和G1的適用場(chǎng)景。筆試?yán)锝?jīng)常讓你“簡(jiǎn)單描述對(duì)象從創(chuàng)建到被回收的完整過程”你就得按這個(gè)鏈路來答new出來的對(duì)象先分配在Eden區(qū)Eden區(qū)滿了觸發(fā)Minor GC存活對(duì)象進(jìn)入Survivor區(qū)并年齡1年齡達(dá)到15默認(rèn)閾值后晉升到老年代老年代滿了觸發(fā)Major GC或Full GC。把這個(gè)流程說順了比零散背一百個(gè)概念都管用。2.2 集合類源碼級(jí)考點(diǎn)與易錯(cuò)點(diǎn)集合類這塊A卷常見問法是“ArrayList和LinkedList的區(qū)別”但這個(gè)題想拿高分不能只說一個(gè)數(shù)組一個(gè)鏈表。我建議從三個(gè)維度展開底層數(shù)據(jù)結(jié)構(gòu)、插入刪除的時(shí)間復(fù)雜度、內(nèi)存占用。ArrayList基于動(dòng)態(tài)數(shù)組查詢快O(1)但指定位置插入刪除需要移動(dòng)元素O(n)LinkedList基于雙向鏈表插入刪除快但查詢需要遍歷O(n)而且每個(gè)節(jié)點(diǎn)還要額外存儲(chǔ)前后指針內(nèi)存占用更大。實(shí)際開發(fā)中LinkedList的使用頻率其實(shí)很低很多場(chǎng)景下ArrayList完全夠用。另一個(gè)高頻考點(diǎn)是HashSet和HashMap的關(guān)系以及TreeMap的排序原理。HashSet底層就是包裝了一個(gè)HashMap存值時(shí)value固定為一個(gè)常量對(duì)象TreeMap基于紅黑樹key必須實(shí)現(xiàn)Comparable接口或者在構(gòu)造時(shí)傳入Comparator這樣才能保證迭代順序。很多人會(huì)忽略ConcurrentHashMap但這類“并發(fā)安全集合”恰恰是后端筆試的寵兒。要記住JDK 1.8之后ConcurrentHashMap已經(jīng)拋棄了分段鎖改用CAS synchronized對(duì)桶的頭節(jié)點(diǎn)加鎖鎖粒度更細(xì)并發(fā)性能更好。易錯(cuò)點(diǎn)提醒HashSet允許存nullTreeSet不允許存null因?yàn)椴迦雗ull時(shí)無法比較大小會(huì)拋NPE。這種細(xì)節(jié)題往往藏在選擇題里刷題時(shí)多留個(gè)心眼。2.3 數(shù)據(jù)庫部分索引、事務(wù)隔離級(jí)別與SQL調(diào)優(yōu)數(shù)據(jù)庫是后端筆試的重頭戲??峒覙稟卷在這一塊的核心考點(diǎn)有三個(gè)索引的底層結(jié)構(gòu)、事務(wù)隔離級(jí)別、以及慢SQL的排查思路。索引部分我建議你畫B樹示意圖來輔助記憶考試時(shí)雖然不能畫圖但腦子里的圖能幫你理清邏輯。B樹的非葉子節(jié)點(diǎn)不存儲(chǔ)數(shù)據(jù)只存儲(chǔ)索引鍵因此同樣大小的頁可以容納更多鍵樹的高度更低磁盤IO次數(shù)更少葉子節(jié)點(diǎn)通過鏈表相連天然適合范圍查詢。這一特性就是MySQL InnoDB選擇B樹而不是B樹或紅黑樹的核心原因。另一個(gè)常被問到的問題是“為什么索引能加快查詢但不宜建太多”因?yàn)樗饕旧硪彩谴鎯?chǔ)結(jié)構(gòu)寫操作時(shí)要同步更新索引索引過多會(huì)導(dǎo)致插入、更新、刪除的性能下降。事務(wù)隔離級(jí)別這塊MySQL默認(rèn)是REPEATABLE READ可重復(fù)讀這一點(diǎn)和很多教材里以READ COMMITTED為默認(rèn)值的描述不同答題時(shí)一定要以MySQL為準(zhǔn)。四個(gè)級(jí)別的區(qū)別用一句話概括READ UNCOMMITTED讀未提交能讀到別人沒提交的數(shù)據(jù)存在臟讀READ COMMITTED讀已提交解決臟讀但存在不可重復(fù)讀REPEATABLE READ可重復(fù)讀解決不可重復(fù)讀但存在幻讀MySQL通過MVCC多版本并發(fā)控制和間隙鎖next-key lock在絕大多數(shù)場(chǎng)景下避免了幻讀SERIALIZABLE串行化隔離最徹底但性能最低。SQL調(diào)優(yōu)題通常給你一段慢SQL讓你分析原因并優(yōu)化?;卮鹛茁芬错樞騺硐扔肊XPLAIN查看執(zhí)行計(jì)劃看是否走了索引、有沒有全表掃描再看type字段從const、eq_ref、ref、range到index、ALL性能依次遞減然后檢查有沒有在索引列上使用函數(shù)或隱式類型轉(zhuǎn)換這會(huì)導(dǎo)致索引失效最后考慮是否需要使用覆蓋索引來避免回表。2.4 緩存部分Redis的數(shù)據(jù)結(jié)構(gòu)與緩存一致性Redis在酷家樂這類互聯(lián)網(wǎng)公司的筆試中出現(xiàn)頻率極高。A卷的常見問法有幾種Redis支持哪些數(shù)據(jù)結(jié)構(gòu)、各自的應(yīng)用場(chǎng)景是什么緩存穿透、緩存擊穿、緩存雪崩的區(qū)別與解決方案如何保證緩存和數(shù)據(jù)庫的一致性。數(shù)據(jù)結(jié)構(gòu)這部分除了String、Hash、List、Set、ZSet這五種基礎(chǔ)類型我建議你也了解一下Bitmap、HyperLogLog、Geo等擴(kuò)展類型。比如UV統(tǒng)計(jì)可以用HyperLogLog誤差率在0.81%左右內(nèi)存占用極低附近的人可以用Geo簽到打卡場(chǎng)景可以用Bitmap。筆試時(shí)提到這些場(chǎng)景化應(yīng)用會(huì)讓閱卷人對(duì)你的實(shí)戰(zhàn)能力刮目相看。緩存三大問題是筆試/面試的必考題答題時(shí)一定要把概念區(qū)分清楚緩存穿透查詢一個(gè)根本不存在的數(shù)據(jù)請(qǐng)求直接打到數(shù)據(jù)庫。解決方案是緩存空值設(shè)置較短過期時(shí)間或者使用布隆過濾器先攔截。緩存擊穿某個(gè)熱點(diǎn)key過期瞬間大量請(qǐng)求同時(shí)打到數(shù)據(jù)庫。解決方案是互斥鎖只讓一個(gè)線程去重建緩存或者設(shè)置熱點(diǎn)key永不過期后臺(tái)異步更新。緩存雪崩大量key同時(shí)過期或者Redis實(shí)例宕機(jī)導(dǎo)致數(shù)據(jù)庫壓力暴增。解決方案是過期時(shí)間加隨機(jī)值或多級(jí)緩存或Redis集群高可用。緩存一致性是一個(gè)經(jīng)典的“沒有標(biāo)準(zhǔn)答案”的題。比較公認(rèn)的偏穩(wěn)妥方案是“Cache Aside Pattern”讀的時(shí)候先讀緩存讀不到再讀數(shù)據(jù)庫然后回填緩存寫的時(shí)候先更新數(shù)據(jù)庫再刪除緩存。為什么是“刪除緩存”而不是“更新緩存”因?yàn)楦戮彺媸菍懖僮骺赡苌婕皬?fù)雜計(jì)算而且一個(gè)key可能被多次更新刪除緩存可以等到真正讀的時(shí)候再重建成本更低。當(dāng)然這方案也有缺陷就是更新數(shù)據(jù)庫和刪除緩存之間存在時(shí)間窗口理論上可能讀到臟數(shù)據(jù)。可選的補(bǔ)償方案有消息隊(duì)列異步重試、訂閱數(shù)據(jù)庫binlog來刪除緩存等答題時(shí)能把方案說全并指出各自的取舍就是高分答案。2.5 Spring生態(tài)與工程化IOC、AOP與Maven依賴管理Spring相關(guān)題目在酷家樂A卷中占據(jù)一定比例這和實(shí)際業(yè)務(wù)開發(fā)直接相關(guān)。核心考點(diǎn)集中在IOC控制反轉(zhuǎn)、AOP面向切面編程、 Spring Boot的自動(dòng)配置原理。IOC不能只答“把對(duì)象的創(chuàng)建交給Spring容器管理”要能講清楚這樣做的好處是解耦以及底層依賴反射機(jī)制。比如你寫了一個(gè)UserService在它里面注入U(xiǎn)serMapper如果沒有Spring你得手動(dòng)new UserMapper()一旦UserMapper的構(gòu)造函數(shù)變了UserService也要跟著改。用了IOC之后你只需要標(biāo)注Autowired或Resource容器會(huì)幫你把依賴注入進(jìn)來開發(fā)和測(cè)試都方便很多。AOP的典型場(chǎng)景是日志記錄、事務(wù)管理、權(quán)限校驗(yàn)。理解AOP的關(guān)鍵是理解代理模式Spring默認(rèn)對(duì)有接口的Bean使用JDK動(dòng)態(tài)代理對(duì)沒有接口的類使用CGLIB代理。這里有個(gè)經(jīng)典易錯(cuò)點(diǎn)Spring Boot 2.x之后spring.aop.proxy-target-class默認(rèn)為true也就是即使有接口也優(yōu)先使用CGLIB。AOP的通知類型包括Before、AfterReturning、AfterThrowing、After、Around執(zhí)行順序是環(huán)繞通知的開始、前置通知、目標(biāo)方法執(zhí)行、環(huán)繞通知的結(jié)束、后置通知、返回/異常通知。答出完整順序的候選人不多你能順下來就很加分。Maven/Gradle的依賴管理題看起來簡(jiǎn)單但翻車率很高。常見考法是給你一段依賴沖突場(chǎng)景讓你分析如何解決。核心原則是“就近優(yōu)先”和“第一聲明優(yōu)先”遇到?jīng)_突可以用mvn dependency:tree查看依賴樹用exclusion排除傳遞性依賴或直接聲明明確版本的依賴。另外要能說清compile、provided、runtime、test這幾個(gè)scope的區(qū)別。2.6 系統(tǒng)設(shè)計(jì)題短鏈服務(wù)、秒殺系統(tǒng)與分布式鎖系統(tǒng)設(shè)計(jì)題是區(qū)分度最大的環(huán)節(jié)??峒覙稟卷的系統(tǒng)設(shè)計(jì)題一般不會(huì)讓你設(shè)計(jì)一個(gè)完整的大型系統(tǒng)而是給出一個(gè)具體的、有明確約束的場(chǎng)景讓你描述方案。常見的場(chǎng)景包括設(shè)計(jì)一個(gè)短鏈接服務(wù)、設(shè)計(jì)一個(gè)秒殺系統(tǒng)、設(shè)計(jì)一個(gè)分布式ID生成器或者“如何設(shè)計(jì)一個(gè)接口的冪等性”。短鏈服務(wù)這個(gè)題非常適合用來展示你的技術(shù)廣度。我提供一個(gè)參考思路短鏈生成的算法用一個(gè)全局自增ID或分布式ID將其轉(zhuǎn)換為62進(jìn)制的字符串0-9a-zA-Z一個(gè)10位的十進(jìn)制數(shù)可以壓縮成6-7位的短碼。跳轉(zhuǎn)邏輯用戶訪問短鏈時(shí)服務(wù)端根據(jù)短碼查映射表找到原始URL后返回302重定向。存儲(chǔ)選型映射關(guān)系可以放在MySQL熱點(diǎn)數(shù)據(jù)加速訪問放在Redis。短碼的哈希碰撞處理用MurmurHash或MD5后截取前幾位如果沖突則再加鹽重哈希。秒殺系統(tǒng)的高并發(fā)問題是經(jīng)典中的經(jīng)典。核心思路是“層層攔截、異步化”前端做限流按鈕置灰、答題驗(yàn)證碼、網(wǎng)關(guān)層做限流令牌桶算法、應(yīng)用層做預(yù)扣庫存Redis原子操作decr、最后異步扣減數(shù)據(jù)庫庫存。同時(shí)要防止超賣數(shù)據(jù)庫庫存字段更新時(shí)使用UPDATE stock SET count count - 1 WHERE id ? AND count 0這種樂觀鎖寫法而不是先查詢?cè)俑?。分布式鎖幾乎必然會(huì)涉及Redis分布式鎖要能說出SETNX加鎖、EXPIRE設(shè)置超時(shí)的基本流程并指出最經(jīng)典的坑加鎖和設(shè)置超時(shí)之間如果進(jìn)程崩潰會(huì)導(dǎo)致鎖永遠(yuǎn)不釋放。因此要使用SET key value NX EX seconds這條原子命令或者借助Redisson的看門狗機(jī)制自動(dòng)續(xù)期。更進(jìn)一步還可以談RedLock算法同時(shí)也要點(diǎn)出RedLock在工程實(shí)踐中其實(shí)備受爭(zhēng)議很多團(tuán)隊(duì)并不推薦因?yàn)樗跇O端場(chǎng)景下并不能保證絕對(duì)安全。能答到這個(gè)層面說明你是真看過不少文章、想過不少場(chǎng)景的。3. 實(shí)戰(zhàn)項(xiàng)目的準(zhǔn)備方法與簡(jiǎn)歷項(xiàng)目包裝筆試題考的是知識(shí)的廣度而簡(jiǎn)歷上的項(xiàng)目體現(xiàn)的是知識(shí)的深度??峒覙稟卷雖然是筆試但你在回答數(shù)據(jù)庫題、并發(fā)題時(shí)能不能結(jié)合項(xiàng)目經(jīng)驗(yàn)來講直接影響到閱卷人對(duì)你的整體印象。所以別忽略項(xiàng)目這條線。3.1 如何把普通項(xiàng)目講出高并發(fā)味道很多同學(xué)的項(xiàng)目是“單機(jī)版管理系統(tǒng)”比如學(xué)生管理系統(tǒng)、博客系統(tǒng)、商城項(xiàng)目看起來沒有高并發(fā)場(chǎng)景但這并不阻礙你展示后端能力。關(guān)鍵是你有沒有主動(dòng)做一些“不那么普通”的設(shè)計(jì)。拿一個(gè)博客系統(tǒng)舉例。你先別急著說CRUD而是想一想文章閱讀數(shù)用Redis的incr命令來做避免頻繁更新MySQL然后定期異步刷回?cái)?shù)據(jù)庫。這是一個(gè)非常經(jīng)典的緩存DB一致性案例筆試考緩存一致性時(shí)你就有話說了。熱門文章列表用ZSet存儲(chǔ)score為閱讀量取TOP N直接ZREVRANGE高效且不傷數(shù)據(jù)庫。圖片上傳用MinIO或OSS對(duì)象存儲(chǔ)而不是存本地磁盤服務(wù)端做斷點(diǎn)續(xù)傳和文件類型校驗(yàn)。權(quán)限控制用Spring Security JWT無狀態(tài)登錄講清楚token為什么放請(qǐng)求頭而不是Cookie。你看同樣是博客系統(tǒng)加上了這幾個(gè)細(xì)節(jié)立馬就從“純CRUD”變成了“有緩存設(shè)計(jì)、有中間件、有鑒權(quán)方案”的項(xiàng)目筆試題里的Redis、JWT、文件存儲(chǔ)相關(guān)內(nèi)容你全都能對(duì)上號(hào)。3.2 前后端分離項(xiàng)目中的后端關(guān)注點(diǎn)既然熱詞里反復(fù)出現(xiàn)前后端分離這里專門強(qiáng)調(diào)一下后端在前后端分離架構(gòu)中要掌握的關(guān)鍵點(diǎn)。第一是跨域CORS。很多同學(xué)本地聯(lián)調(diào)時(shí)遇到跨域問題就只知道加個(gè)CrossOrigin注解筆試如果問“跨域的本質(zhì)是什么”你要能答出瀏覽器同源策略限制的是“JS發(fā)起的請(qǐng)求”服務(wù)端只要在響應(yīng)頭返回Access-Control-Allow-Origin等字段瀏覽器就會(huì)放行。Spring Boot里可以用WebMvcConfigurer統(tǒng)一配置CORS映射也可以加CORS過濾器生產(chǎn)環(huán)境的線上Nginx反向代理同樣能解決跨域。第二是統(tǒng)一響應(yīng)體和全局異常處理。后端接口不能一會(huì)返回{code:0,data:xxx}一會(huì)直接返回一個(gè)字符串。一般項(xiàng)目里會(huì)定義一個(gè)RT或ResultT統(tǒng)一包裝配合RestControllerAdvice做全局異常捕獲把參數(shù)校驗(yàn)異常、業(yè)務(wù)異常、未知異常分別映射到不同的錯(cuò)誤碼。這一個(gè)設(shè)計(jì)能極大提升前后端聯(lián)調(diào)效率也是面試時(shí)展示代碼規(guī)范度的好素材。第三是JWT刷新機(jī)制。很多項(xiàng)目只實(shí)現(xiàn)了登錄后發(fā)一個(gè)token而沒有考慮token過期問題。你可以在項(xiàng)目中引入refresh_token雙token機(jī)制access_token有效期短比如30分鐘refresh_token有效期長(zhǎng)比如7天前端發(fā)現(xiàn)access_token過期后用refresh_token換新這樣既安全又不用頻繁登錄能講清楚這套流程系統(tǒng)設(shè)計(jì)題基本不怕。3.3 本地聯(lián)調(diào)與環(huán)境部署的經(jīng)驗(yàn)筆試和面試階段很多同學(xué)容易忽視“服務(wù)能不能跑起來”這類工程能力但實(shí)際操作中這往往是最能拉開差距的地方??峒覙愤@類公司很看重你能不能獨(dú)立把一個(gè)項(xiàng)目從代碼變成線上服務(wù)。我建議你在準(zhǔn)備階段一定要親手走一遍完整的部署流程本地用Docker起一個(gè)MySQL和Redis用docker-compose.yml統(tǒng)一編排后端項(xiàng)目用Maven的mvn clean package -Dmaven.test.skiptrue打成jar包然后部署到一臺(tái)云服務(wù)器上用nohup java -jar xxx.jar app.log 21 方式啟動(dòng)。要讓一個(gè)項(xiàng)目真正能被訪問還需要配好Nginx反向代理、HTTPS證書以及MySQL和Redis的遠(yuǎn)程訪問權(quán)限。這里面坑非常多。比如云服務(wù)器安全組不放行端口、MySQL默認(rèn)只監(jiān)聽127.0.0.1、Redis沒設(shè)密碼被攻擊入侵這些都是網(wǎng)上隨手一搜就能看到的經(jīng)典事故。你如果能在簡(jiǎn)歷的項(xiàng)目經(jīng)驗(yàn)里寫一句“項(xiàng)目已部署至云服務(wù)器使用Nginx反向代理HTTPS訪問”招聘方的技術(shù)篩選官對(duì)你的工程能力會(huì)明確加分。3.4 Jenkins自動(dòng)化構(gòu)建與持續(xù)集成另一個(gè)容易被忽視但有含金量的點(diǎn)是持續(xù)集成。校招生的項(xiàng)目通常是在本地跑起來就算完事但如果你能引入Jenkins做自動(dòng)化構(gòu)建項(xiàng)目質(zhì)感會(huì)完全不同?;玖鞒淌菍懲甏a推送到Git倉(cāng)庫Jenkins監(jiān)聽倉(cāng)庫變化并觸發(fā)構(gòu)建任務(wù)構(gòu)建腳本里執(zhí)行mvn build或npm run build再通過SSH把產(chǎn)物同步到測(cè)試服務(wù)器實(shí)現(xiàn)“推送即部署”。筆試?yán)锶绻麊柕健叭绾伪WC代碼質(zhì)量”你就可以很自然地帶出這一套流程代碼提交前用mvn test跑單元測(cè)試在Jenkins流水線里加Checkstyle或SpotBugs做靜態(tài)檢查配置SonarQube做代碼質(zhì)量門禁。這一領(lǐng)域經(jīng)常出現(xiàn)的問題是Java版本和Maven版本不匹配、JAVA_HOME環(huán)境變量沒有正確設(shè)置、或者application.yml里的數(shù)據(jù)庫地址還是本地的localhost導(dǎo)致部署后連不上數(shù)據(jù)庫。我的建議是配置文件一律使用Spring Boot的application-{profile}.yml多環(huán)境配置本地上用devProfile服務(wù)器上用prodProfile通過啟動(dòng)參數(shù)--spring.profiles.activeprod切換這樣本地和線上不會(huì)互相污染。4. 復(fù)習(xí)路線的規(guī)劃與資源推薦現(xiàn)在聊一個(gè)更實(shí)際的問題如果要從零開始準(zhǔn)備怎么安排復(fù)習(xí)節(jié)奏我給出一條相對(duì)高效的路線貼合校招時(shí)間線。4.1 階段一夯實(shí)基礎(chǔ)2-3周第一輪重點(diǎn)是Java基礎(chǔ)、集合源碼、JVM、并發(fā)編程。這個(gè)階段不要追求把每個(gè)知識(shí)點(diǎn)都摳到極致而是建立“知識(shí)框架”。我的做法是每天學(xué)一個(gè)大主題比如周一集合、周二JVM、周三并發(fā)每個(gè)主題必須能回答三個(gè)問題它是什么、解決什么問題、底層是怎么做的。推薦的學(xué)習(xí)路徑是“看視頻入門 看博客加深 動(dòng)手寫Demo驗(yàn)證”。視頻適合入門比如B站上口碑不錯(cuò)的Java基礎(chǔ)課博客適合深入像美團(tuán)技術(shù)團(tuán)隊(duì)、阿里中間件團(tuán)隊(duì)的技術(shù)博客都有大量源碼級(jí)文章Demo驗(yàn)證這一步很多人會(huì)省但我強(qiáng)烈建議別省舉一個(gè)例子學(xué)習(xí)線程池時(shí)自己寫一段代碼分別用newCachedThreadPool和自定義ThreadPoolExecutor跑10000個(gè)任務(wù)觀察線程數(shù)和隊(duì)列的變化印象絕對(duì)比背十遍概念深刻。4.2 階段二主攻中間件與數(shù)據(jù)庫2-3周第二階段集中火力攻MySQL、Redis、Spring、消息隊(duì)列。每一塊都要做到“能說出原理能畫出架構(gòu)能解決場(chǎng)景問題”。我提供一個(gè)學(xué)習(xí)清單你可以逐項(xiàng)打勾MySQL存儲(chǔ)引擎InnoDB與MyISAM區(qū)別、索引數(shù)據(jù)結(jié)構(gòu)、聚簇索引與非聚簇索引、事務(wù)隔離級(jí)別與MVCC、EXPLAIN執(zhí)行計(jì)劃分析、慢查詢優(yōu)化。Redis五種基本數(shù)據(jù)結(jié)構(gòu)及使用場(chǎng)景、持久化RDB/AOF區(qū)別與選型、過期刪除與內(nèi)存淘汰策略、緩存穿透擊穿雪崩解決方案、分布式鎖實(shí)現(xiàn)。SpringIOC容器生命周期、Bean的作用域與循環(huán)依賴、AOP代理機(jī)制、Spring Boot自動(dòng)配置原理、Spring MVC請(qǐng)求處理流程。消息隊(duì)列為什么使用消息隊(duì)列解耦、異步、削峰、如何保證消息不丟失、如何保證消息順序消費(fèi)、如何保證冪等。4.3 階段三刷題與做項(xiàng)目并行3-4周第三個(gè)階段是輸出階段。一方面刷筆試題尤其是歷年校招真題刷題時(shí)不要只求做對(duì)而是要分析每道題背后的知識(shí)點(diǎn)另一方面整理自己的項(xiàng)目把之前寫的代碼重新梳理一遍補(bǔ)充前面說的Redis、統(tǒng)一響應(yīng)、JWT、部署等細(xì)節(jié)。刷題時(shí)我建議你準(zhǔn)備一個(gè)“錯(cuò)題本”但不要只抄題目和答案而是記錄“我為什么錯(cuò)”。比如一道數(shù)據(jù)庫索引失效的題做錯(cuò)了你要寫下是因?yàn)闆]看出查詢條件里對(duì)索引列用了LIKE %xxx導(dǎo)致前綴模糊匹配無法走索引。下次遇到類似的題先在腦里過一遍“索引失效的常見場(chǎng)景”清單比如隱式類型轉(zhuǎn)換、對(duì)索引列使用函數(shù)、OR連接非索引列、NOT IN或!操作符、前導(dǎo)模糊匹配等。這樣刷題才有增量?jī)r(jià)值。4.4 高頻考點(diǎn)速查表為了方便你自測(cè)我把后端A卷的高頻考察點(diǎn)按“必須掌握、建議掌握、了解即可”三個(gè)等級(jí)整理了一下等級(jí)考點(diǎn)準(zhǔn)備建議必須掌握HashMap、ConcurrentHashMap、線程池參數(shù)、JVM內(nèi)存模型、MySQL索引與事務(wù)、Redis基本結(jié)構(gòu)與緩存問題、Spring IOC/AOP、Maven生命周期能夠流利輸出達(dá)到面試時(shí)脫口而出的水平必須掌握接口冪等性、分布式鎖、統(tǒng)一異常處理、JWT認(rèn)證、前后端分離跨域能結(jié)合項(xiàng)目說清楚具體實(shí)現(xiàn)方案建議掌握B樹與哈希索引的區(qū)別、MVCC內(nèi)部原理、Redis持久化、消息隊(duì)列基本使用與可靠性能說清原因和應(yīng)用場(chǎng)景不需要手寫源碼了解即可Raft算法細(xì)節(jié)、ZooKeeper內(nèi)部原理、Netty線程模型、SkyWalking鏈路追蹤能用自己的話概述即可不深入細(xì)節(jié)5. 筆試現(xiàn)場(chǎng)的時(shí)間分配和答題策略最后這部分我想聊聊真正坐在考場(chǎng)里面對(duì)一份后端A卷時(shí)的答題技巧。這在你刷題時(shí)就可以提前演練。5.1 時(shí)間分配與做題順序拿到的試卷先別急著從頭寫到尾?;?-2分鐘瀏覽整份試卷標(biāo)記出題目類型和預(yù)估耗時(shí)。我的策略是先做系統(tǒng)設(shè)計(jì)題再做數(shù)據(jù)庫題然后是Java基礎(chǔ)題最后是框架與工程化題。為什么是這個(gè)順序因?yàn)橄到y(tǒng)設(shè)計(jì)題分值高、思路開放趁頭腦清醒時(shí)能想得更全面Java基礎(chǔ)題往往比較機(jī)械放在后面寫完就算。時(shí)間分配上如果筆試總時(shí)長(zhǎng)是90分鐘建議基礎(chǔ)題控制在40分鐘以內(nèi)數(shù)據(jù)庫和緩存題30分鐘系統(tǒng)設(shè)計(jì)題20分鐘。不要在一道選擇題上糾結(jié)太久拿不準(zhǔn)的做個(gè)標(biāo)記等全部寫完再回頭檢查。5.2 不會(huì)的題怎么做校招筆試遇到不會(huì)的題是常態(tài)。首先要區(qū)分“真的不會(huì)”和“暫時(shí)沒思路”。如果是后者先把題目重新讀一遍很多時(shí)候不是你不會(huì)而是漏看了關(guān)鍵條件。比如題面可能寫著“MySQL默認(rèn)隔離級(jí)別”你沒看清楚直接答成了“讀已提交”。如果是真的不會(huì)也盡量不要空著。填空題和問答題可以寫一些相關(guān)的知識(shí)點(diǎn)至少讓閱卷人看到你有一定理解。比如問你“Redis如何實(shí)現(xiàn)分布式鎖”你記不住Redisson的完整機(jī)制但至少可以寫出SETNX加鎖、EXPIRE設(shè)置過期時(shí)間的基本流程再說明存在的坑。這比完全不寫要強(qiáng)得多而且可能剛好落在給分點(diǎn)上。5.3 常見但容易答錯(cuò)的細(xì)節(jié)這里分享幾個(gè)我在復(fù)盤試卷時(shí)發(fā)現(xiàn)的普遍易錯(cuò)點(diǎn)值得單獨(dú)記一下ArrayList默認(rèn)容量是10不是16擴(kuò)容后變?yōu)樵瓉淼?.5倍oldCapacity (oldCapacity 1)。MySQL默認(rèn)隔離級(jí)別是REPEATABLE READ不是READ COMMITTED。Spring Boot內(nèi)嵌的Web服務(wù)器默認(rèn)是Tomcat不是Jetty。Transactional默認(rèn)只在RuntimeException和Error時(shí)回滾如果拋出受檢異常默認(rèn)不回滾需要指定rollbackFor Exception.class。HashMap在JDK 1.7時(shí)頭插法會(huì)形成死循環(huán)1.8改為尾插法后解決但并不同時(shí)等價(jià)于線程安全。Redis是單線程模型處理命令但持久化、過期刪除在子進(jìn)程中執(zhí)行所以不要答成“Redis所有操作都是單線程”。這些細(xì)節(jié)往往就是選擇題里的選項(xiàng)陷阱平時(shí)不留意考場(chǎng)上很容易被繞進(jìn)去。6. 關(guān)于簡(jiǎn)歷投遞與面試心態(tài)的一點(diǎn)個(gè)人建議筆試只是校招鏈路中的一環(huán)但它的準(zhǔn)備過程會(huì)直接影響你后續(xù)面試的效果。我見過不少同學(xué)筆試過了卻在技術(shù)面階段因?yàn)轫?xiàng)目講不清楚被刷掉根源就在于準(zhǔn)備筆試時(shí)只刷題、沒有同步整理項(xiàng)目。所以我建議你從準(zhǔn)備筆試的第一天起就同步維護(hù)一份自己項(xiàng)目的“技術(shù)亮點(diǎn)清單”每學(xué)到一個(gè)新知識(shí)點(diǎn)就去想一想能不能應(yīng)用到你的項(xiàng)目里。這樣筆試不但不會(huì)和面試割裂反而互相成就。另一個(gè)實(shí)際的建議是投遞簡(jiǎn)歷不要扎堆也不要有“一定要進(jìn)某家公司”的執(zhí)念。騰訊、阿里、字節(jié)、美團(tuán)是很多人的目標(biāo)但酷家樂這種垂直行業(yè)的頭部公司技術(shù)氛圍和成長(zhǎng)空間其實(shí)也同樣值得考慮。筆試題的覆蓋面也能反映出公司的技術(shù)側(cè)重你多考幾家就相當(dāng)于多獲得幾份“技術(shù)方向參考指南”對(duì)后續(xù)職業(yè)選擇很有幫助。在心態(tài)上校招是一個(gè)漫長(zhǎng)且充滿不確定性的過程筆試失利真的不代表你不行。我當(dāng)年也掛過好幾家公司的筆試后來復(fù)盤發(fā)現(xiàn)大多是時(shí)間分配不合理或者在一道選擇題上鉆了牛角尖而不是能力問題。每一次筆試后一定要做復(fù)盤把不確定的題重新查一遍三個(gè)月后你會(huì)發(fā)現(xiàn)自己知識(shí)的漏洞越來越少拿到offer也就成了水到渠成的事。最后再分享一個(gè)小技巧筆試前可以拿一張紙把你已經(jīng)熟練掌握的知識(shí)點(diǎn)導(dǎo)圖默寫出來不需要畫得多精致關(guān)鍵是帶你進(jìn)入“整體掃描”的狀態(tài)。真正到了考場(chǎng)上你會(huì)發(fā)現(xiàn)自己比想象中沉穩(wěn)得多。