面試題之高頻面試題

最近開始面試了,410面試了一家公司 針對自己薄弱的面試題庫,深入了解下,也應付下面試。在這里先祝愿大家在現有公司好好沉淀,定位好自己的目標,在自己的領域上發光發熱,在自己想要的領域上(技術管理、項目管理、業務管理等)越走越遠!希望各位面試都能穩過,待遇都是杠杠的!因為內心還是很慌,所以先整理所有高頻的面試題出來,包含一些業務場景及java相關的所有面試。

JAVA基礎


1.java的各種鎖

樂觀鎖、悲觀鎖、公平鎖,非公平鎖、排他鎖、共享鎖、重入鎖、偏向鎖、重量級鎖

  • 基礎鎖概念:
    • 樂觀鎖:
      • 假設并發沖突很少發生
      • 實現方式:版本號機制、CAS操作
      • 典型實現:Atomic類、StampedLock的樂觀讀
      • 使用場景:讀多寫少,沖突概率低
    • 悲觀鎖:
      • 假設并發沖突經常發生
      • 實現方式:synchronized、ReentrantLock
      • 典型特點:先加鎖再訪問
      • 使用場景:寫多讀少,重讀概率高
    • 公平鎖:
      • 按請求順序分配鎖
      • 實現:ReentrantLock(true)
      • 優點: 避免線程饑餓
      • 缺點:吞吐量較低
    • 非公平鎖:
      • 允許線程“插隊”獲取鎖
      • 實現:synchronized、ReentrantLock(false)
      • 優點:吞吐量高
      • 缺點:可能造成線程饑餓
    • 排他鎖(獨占鎖)
      • 同一個時刻只允許有一個線程持有
      • 實現:synchronized、ReentrantLock、ReentrantReadWriteLock.WriteLock
    • 共享鎖:
      • 允許多個線程共同持有
      • 實現:ReentrantReadWriteLock.ReadLock、Semaphore
  • 高級鎖特征
    • 重入鎖(Reentrant Lock)
      • 線程可以重復獲取已持有的鎖
      • 實現:synchronized、ReentrantLock
      • 鎖技術:每次重入計數+1,完全釋放需解鎖相同次數
      • 鎖膨脹過程(JVM優化)
      • 無鎖狀態:初始狀態
    • 偏向鎖:優化單線程重復訪問
    • 輕量級鎖:多線程輕度競爭時自旋等待
    • 重量級鎖:競爭激烈時轉為OS互斥量
    • 自旋鎖(Spin Lock)
      • 線程不立即阻塞,而是循環嘗試獲取鎖
      • 減少線程上下文切換開銷
      • 使用場景:鎖持有時間短的場景
  • 特殊用途鎖:
    • 分段鎖(segment Lock)
      • 將數據分段,每段獨立加鎖
      • 典型實現:ConcurrentHashMap(JDK7版本)
      • 提高并發度,減少鎖競爭
    • 郵筒鎖(mailbox Lock)
      • 用于線程間通信的同步機制
      • 類似生產者-消費者模式中的交換區
    • 條件鎖(condition Lock)
      • 基于條件的等待/通知機制
      • 實現:condition 接口
      • 比Object.wait()/notify更靈活
    • 分布式鎖:
      • 跨JVM進程的鎖機制
      • 常見實現:redis、zookeeper
      • 典型方案:RedLock算法
  • JUV包中的并發工具
    • 信號量(semaphore)
      • 控制同時訪問特定資源的線程數量
      • 可做流量控制
    • 倒計時門閂(countDownLath)
      • 等待多個線程完成后再繼續
    • 循環柵欄(cyclicBarrier)
      • 讓一組線程互相等待到達屏障點
    • 相位器(Phaser)
      • 更靈活的多階段同步屏障
  • 其他重要概念
    • 鎖消除(Lock Elimination)
      • JVM在即時編譯時消除不必要的鎖
      • 基于逃逸分析判斷對象不會逃逸出當前線程
    • 鎖粗化(Lock coarsening)
      • 將多個鎖的鎖操作合并成一個更大范圍的鎖
      • 減少頻繁加鎖解鎖的開銷
    • 死鎖(Dead Lock)
      • 多線程互相等待對方釋放鎖
      • 四個必要條件:互斥條件、請求與保持、不可剝奪、循環等待
    • 活鎖(live lock)
      • 線程不斷改變但無法繼續執行
      • 類似“謙讓過度”的情況
    • 鎖饑餓(Lock starvation)
      • 某些線程長期無法獲取資源
      • 常見于不合理的鎖分配策略
  • 鎖的選擇建議:
    • 優先考慮內置鎖:簡單的synchronized
    • 需要靈活時:選擇ReentrantLock或者ReentrantReadWriteLock
    • 讀多寫少場景:考慮stampedLock的樂觀讀
    • 高度并發計數:使用Atomic類
    • 資源池控制:使用semaphore
    • 線程協調:根據場景選擇CountDownLatch/CyclicBarrier/Phaser
Q:分布式鎖的實現邏輯?

A:分布式鎖是解決分布式系統中資源互斥訪問的關鍵技術.

  • 分布式鎖核心特性要求:
    • 互斥性:同一時刻只有一個客戶端能持有鎖
    • 防死鎖:持有鎖的客戶端崩潰后鎖能自動釋放
    • 容錯性:部分節點宕機不影響鎖服務的可用性
    • 可重入:同一客戶端多次獲取同一把鎖
    • 高性能:獲取/釋放的操作要高效
  • 主流實現方案:
    • 基于數據庫實現:
      • 實現流程:
        • 創建數據庫表專門用來做分布式鎖,每次分配一個鎖就在數據庫插入一條數據,釋放則刪除
      • 特點:
        • 簡單易實現,性能較差(增加了IO開銷)
        • 需要處理死鎖和超時問題
        • 可考慮樂觀鎖版本號機制優化
    • 基于redis實現
      • 實現流程:
        • setnx方案:通過redis的setnx獲取鎖,當返回成功時處理業務邏輯,其底層通過LUA腳本保證原子性
        • RedLock算法(Redis官方推薦):嘗試獲取所有節點的鎖,并獲取耗時檢查
      • 特點:
        • 性能優異
        • 需要處理鎖續期問題(看門狗機制-只要客戶端還活著即jvm進程未崩潰,就主動續約)
        • RedLock需要至少5個Redis主節點
        • 網絡分區可能出現腦裂問題
    • 基于zookeeper實現
      • 實現流程:
        • 創建臨時有序節點
        • 獲取所有子節點
        • 判斷是否最小節點,是則獲取鎖成功,否則監聽前一個節點阻塞等待
      • 特點:
        • 可靠性高(cp系統)
        • 性能低于Redis方案
        • 天然解決鎖釋放問題(臨時節點)
        • 實現相對復雜
    • 基于Etcd的實現
      • 實現流程:
        • 獲取鎖(租約機制)
        • 保持心跳持續鎖
        • 釋放鎖
      • 特點:
        • 基于Raft協議強一致
        • 支持租約自動過期
        • 比zk更易實現
    • 關鍵性問題解決方案:
      • 鎖續期問題:
        • redis方案:啟動后臺線程定期延長鎖過期時間(Redisson的watchdog機制)
        • zookeeper方案:會話心跳自動維持
      • 鎖誤釋放問題
        • 每個鎖綁定唯一客戶端標識(UUID)
        • 釋放時校驗標識(Lua腳本保證原子性)
      • 鎖等待問題:
        • 實現公平鎖(zk順序節點)
        • 設置合理的等待超時時間
      • 集群故障處理
        • redis:主從切換可能導致鎖丟失(RedLock可緩解)
        • zk:半數以上節點存活即可工作

各方案對比

方案一致性性能實現復雜度適用場景
數據庫簡單低頻簡單場景
Redis中等高頻、允許偶爾失效
RedLock較強復雜高可靠性要求
Zookeeper復雜CP系統、分布式協調
Etcd中高中等Kubernetes環境、CP系統
  • 最佳實現:
    • 始終設置合理的鎖超時時間
    • 實現鎖的可重入人邏輯(如計數機制)
    • 添加鎖獲取失敗的重試策略(帶退避算法)
    • 關鍵操作記錄審計日志
    • 生產環境建議使用成熟框架
      • java:redisson、curator
      • go:etcd/clientv3
      • python:python-redis-lock
Q:redlock如何保障redis主從切換時鎖丟失問題?

問題描述:普通的redis主從架構中:客戶端向主節點申請鎖,主節點異步復制鎖的信息到從節點中。若主節點崩潰,從節點升級為主節點時,可能尚未接受到鎖信息,導致新主節點上沒有鎖信息,其他客戶端可以獲取相同的鎖,破壞了互斥性

A:RedLock通過多節點獨立獲取+多數表決機制解決該問題。

  • 部署多個完全獨立的redis主節點(無主從關系,建議至少部署5個)
  • 客戶端依次向所有節點申請鎖
  • 當獲取多數節點(N/2+1)的鎖時,才算獲取成功
  • 鎖的有效時間包含獲取鎖的時間消耗
Q:Redisson看門狗機制如何實現業務未處理完成,鎖會自動續約?

A:Redisson的看門狗機制是其分布式鎖實現的核心特性之一,它解決了業務處理時間超過鎖超時時間的問題。

  • 核心原理:
    • 自動續期機制:當客戶端獲取鎖后,會啟動一個后臺線程定期檢查并延長鎖的持有時間
    • 健康檢查:只要客戶端還“活著”(JVM進程未崩潰),鎖就不會因為超時被意外釋放
    • 默認配置:
    • 鎖默認超時時間:30秒
    • 續期檢查間隔:超時時間的1/3(默認10秒一次)
Q:什么是死鎖,如何避免?

A:死鎖(Deadlock)是指兩個或多個進程/線程在執行過程中,由于競爭資源彼此通信而造成的一種互相等待的現象,若無外力干涉,這些進程/線程都將無法繼續執行下去

  • 死鎖的必要提交:
    • 互斥條件:資源一次只能由一個進程占用
    • 請求與保持條件:進程持有至少一個資源,并等待獲取其他被占用資源
    • 不可剝奪條件:已分配給進程的資源,不能被其他進程強行奪取
    • 循環等待條件:存在一個進程等待的循環鏈
  • 死鎖常見場景:
    • 數據庫死鎖
    • java多線程死鎖
  • 預防策略(破壞必要條件)
必要條件破壞方法
互斥條件使用共享資源(如讀寫鎖)
請求與保持條件一次性申請所有資源(All-or-Nothing)
不可剝奪條件允許搶占資源(設置超時/中斷)
循環等待條件資源有序分配法(對所有資源排序,按固定順序申請)
  • 避免策略(運行時判斷)
    • 銀行家算法:系統在分配資源先計算分配的安全性
    • 資源分配圖算法:檢查圖中是否存在環
  • 檢查與恢復
    • 檢查機制:
      • 定期檢查資源分配圖
      • 使用等待圖(wait-for graph)檢測環
    • 恢復措施:
      • 進程終止:強制終止部分死鎖進程
      • 資源搶占:回滾并搶占部分資源
  • 解決:
    • 統一加鎖順序:通過固定的順序打破循環等待條件
      • 按照固定順序加鎖,避免線程之間交叉申請資源
    • 設置超時機制:即使退出等待狀態避免僵局
      • 設置超時時間,打破占有且等待條件,通過try lock設置超時機制,未獲取到鎖時,退出等待
    • 使用無鎖算法和并發工具類,盡量避免顯示加鎖
      • java.util.concurrent包下面的安全容器與工具
        • concurrentHashMap
        • ConcurrentLinkedQueue
        • AtomicInteger
        • 盡量避免使用顯示加鎖
    • 減少鎖的顆粒度,限制同步范圍優先性能
      • 盡量減少鎖的顆粒度,縮小鎖的臨界區,減少線程之間的競爭
    • 避免鎖嵌套
      • 盡量減少一個線程持有多個鎖,或者多個線程相互金正同一組鎖的場景
    • 檢查死鎖
      • 通過死鎖監控工具(JConsole、visualVM中的線程視圖)分析線程狀態并排查

2.JVM垃圾回收原理及如何優化
  • 垃圾回收核心概念:
    • 可達性分析算法:通過GC Roots對象作為起點,向下搜索引用鏈,不可達的對象即為垃圾
    • GC Roots包括:
      • 虛擬機棧中引用的對象
      • 方法區中類靜態屬性引用的對象
      • 方法區中常用引用的對象
      • 本地方法棧中JNI引用的對象
  • 內存分代模型
    • JVM將堆內存劃分為不同的代際
堆內存結構
┌───────────────────────┐
│       Young Gen       │
│ ┌─────┐ ┌─────┐ ┌─────┐│
│ │Eden │ │S0   │ │S1   ││
│ └─────┘ └─────┘ └─────┘│
├───────────────────────┤
│       Old Gen         │
└───────────────────────┘
│   Permanent Gen/Metaspace  │
└───────────────────────┘
  • 主流的垃圾回收器:
    • 新生代回收器:
      • serial:單線程,復制算法
      • parNew:serial的多線程版本
      • parallel scavenge:吞吐量有限
    • 老年代回收器:
      • serial old:單線程,標記-整理算法
      • parallel old:parallel scavenge的老年代斑斑
      • CMS:低延遲,標記-清楚算法
    • G1回收器:
      • 面向服務端應用
      • 將堆劃分為多個Region
      • 可預測的停頓時間模型
    • ZGC/Shenandoah
      • JDK11+引入的超低延遲回收器
      • 停頓時間不超過10ms
      • 支持TB級堆內存
  • 垃圾回收優化策略:
    • 關鍵JVM參數:
      • 設置初始和最大堆大小,老年代和新生代比例,eden/survivor比例,啟用G1回收器,啟用CMS回收器
    • 優化原則:
      • 內存分配優化:
        • 避免過大的對象直接進入老年代
        • 合理設置新生代大小,減少過早晉升
        • 監控對象年齡分布,調整晉升閾值
      • GC策略選擇:
        • 吞吐量優先:parallel scavenge+parallel old
        • 低延遲優先:CMS/G1/ZGC
        • 大內存應用:G1/ZGC/Shenandoah
  • 常見問題解決方案:
    • 頻繁full gc
      • 檢查內存泄露
      • 調整老年代大小
      • 優先對象分配模式
    • 長時間GC停頓
      • 考慮切換到G1或者ZGC
      • 減少存活對象數量
    • 增加堆內存
      • 內存碎片問題:
        • 使用標記-整理算法回收器
        • 適當減少-xxcmsInitiatingOccupancyFraction值
    • 定期重啟服務
      • 使用優化技巧
        • 對象池化:復用對象減少GC壓力
        • 本地緩沖控制:合理使用weak /soft reference
        • 集合優化:預估大小避免擴容
        • 流處理:及時關閉資源
      • 監控工具:
        • jstat -gcutil pid
        • visualVM
        • GCViewer分析GC日志
        • Arthas實時診斷
  • 不同場景下優化建議
    • web應用
      • 推薦G1回收器,關注會話對象生命周期,優化緩沖策略
    • 大數據處理
      • 增加新生代比例,考慮使用parallel回收器,監控大對象分配
    • 金融交易系統:
      • 優先考慮ZGC/shenandoah,嚴格控制停頓時間,減少不可預測的對象分配
3.工作中如何使用線程的?

? ? ? ? 框架級別的,在啟動框架時,利用多線程來處理一些批量的任務,比如spring boot在啟動的時候通過多線程來過濾自動配置類,當然他的線程是在啟動的時候過濾下,后續就關閉了。但是如果我們是對外提供的接口,如果使用線程池,有可能在高并發的場景下,創建大量的線程,從而導致過度的消息系統的資源,甚至拉垮系統,所以我們使用線程池合理的創建執行到銷毀來管理系統。

  • 基礎的使用:通過直接創建線程、線程池來使用
  • 典型應用:通過異常處理,主流程不需要等待結果的操作;并行計算,CPU密集型任務拆分;定時任務;生產者-消費者模式
  • 線程池類型選擇
    • CPU密集型:固定大小線程池
    • IO密集型:可緩存線程池
    • 定時/延遲任務:調度線程池
    • 任務優先級管理:自定義ThreadPoolExecutor
  • 推薦自定義線程池配置
  • 關鍵參數建議:
    • 核心線程數:CPU密集型設為CPU核心數+1,IO密集型可設更高
    • 隊列容量:根據系統負載設置,避免OOM
    • 拒絕策略
      • AbortPolicy:默認,拋出異常
      • callerRunsPolicy:由調用線程執行
      • DiscardOldestPolicy:丟棄最舊任務
      • DiscardPolicy:默認丟棄
  • Q:線程常見問題:
    • 線程泄露,線程數持續增長不釋放
    • 解決:
      • 確保正確暴斃線程池、使用有界隊列、設置合理的線程存活時間
      • 死鎖預防:防止死鎖四步走
      • 性能監控:監控線程池狀態

Q:使用什么方式創建線程池?為何不適用jdk內置的executors創建線程池?

4.工作中如何使用策略模式+依賴注入?

在工作中總是會有通過某些枚舉來判斷做什么操作,比如在訂單支付接口中,我們需要判斷用戶提交的是微信支付還是支付寶支付,如果后面支付的方式越來越多,代碼會越來越長,那么如何使用策略模式來改造這種現象呢?

原始代碼:

public class PaymentService {public void processPayment(String paymentType, BigDecimal amount) {if ("ALIPAY".equals(paymentType)) {// 支付寶支付邏輯System.out.println("處理支付寶支付: " + amount);} else if ("WECHAT".equals(paymentType)) {// 微信支付邏輯System.out.println("處理微信支付: " + amount);} else if ("UNIONPAY".equals(paymentType)) {// 銀聯支付邏輯System.out.println("處理銀聯支付: " + amount);} else {throw new IllegalArgumentException("不支持的支付方式");}}
}

上面代碼違反了開閉原則,每次新增支付方式需要調整原代碼,方法臃腫,隨著支付方式越來越多,會越來越長,難以單獨測試某中支付方式,支付邏輯與其他代碼邏輯耦合。

方式一:策略模式改造:定義策略接口

public interface PaymentStrategy {/*** 支付處理方法* @param amount 支付金額* @return 支付結果*/PaymentResult pay(BigDecimal amount);/*** 是否支持當前支付類型* @param paymentType 支付類型* @return 是否支持*/boolean supports(String paymentType);
}// 支付結果封裝
public class PaymentResult {private boolean success;private String message;private String transactionId;// getters/setters
}

方式一:策略模式改造:實現具體策略模式,以支付寶方式為例

public class AlipayStrategy implements PaymentStrategy {@Overridepublic PaymentResult pay(BigDecimal amount) {// 調用支付寶SDK的具體實現System.out.println("支付寶支付處理中,金額: " + amount);PaymentResult result = new PaymentResult();result.setSuccess(true);result.setTransactionId("ALI" + System.currentTimeMillis());return result;}@Overridepublic boolean supports(String paymentType) {return "ALIPAY".equalsIgnoreCase(paymentType);}
}

方式一:?策略模式改造:創建策略工廠

public class PaymentStrategyFactory {private final List<PaymentStrategy> strategies;// 通過構造器注入所有策略public PaymentStrategyFactory(List<PaymentStrategy> strategies) {this.strategies = strategies;}public PaymentStrategy getStrategy(String paymentType) {return strategies.stream().filter(s -> s.supports(paymentType)).findFirst().orElseThrow(() -> new IllegalArgumentException("不支持的支付方式: " + paymentType));}
}

方式一:策略模式改造:改造支付服務

@Service
public class PaymentService {private final PaymentStrategyFactory strategyFactory;// 構造器注入public PaymentService(PaymentStrategyFactory strategyFactory) {this.strategyFactory = strategyFactory;}public PaymentResult processPayment(String paymentType, BigDecimal amount) {PaymentStrategy strategy = strategyFactory.getStrategy(paymentType);return strategy.pay(amount);}
}

方式二:springboot集成優化 自動注冊策略bean

@Configuration
public class PaymentConfig {@Beanpublic PaymentStrategyFactory paymentStrategyFactory(List<PaymentStrategy> strategies) {return new PaymentStrategyFactory(strategies);}@Beanpublic PaymentStrategy alipayStrategy() {return new AlipayStrategy();}@Beanpublic PaymentStrategy wechatPayStrategy() {return new WechatPayStrategy();}@Beanpublic PaymentStrategy unionPayStrategy() {return new UnionPayStrategy();}
}

方式二:springboot集成優化 使用枚舉優化支付類型

public enum PaymentType {ALIPAY("ALIPAY", "支付寶"),WECHAT("WECHAT", "微信支付"),UNIONPAY("UNIONPAY", "銀聯支付");private final String code;private final String name;// constructor/getters
}

方式二:springboot集成優化 策略接口改進,使用枚舉

public interface PaymentStrategy {PaymentResult pay(BigDecimal amount);// 改為支持PaymentType枚舉boolean supports(PaymentType paymentType);
}

?方式三:優化方案:策略+模板方法模式結合

public abstract class AbstractPaymentStrategy implements PaymentStrategy {@Overridepublic final PaymentResult pay(BigDecimal amount) {// 1. 參數校驗validate(amount);// 2. 執行支付PaymentResult result = doPay(amount);// 3. 記錄日志logPayment(result);return result;}protected abstract PaymentResult doPay(BigDecimal amount);private void validate(BigDecimal amount) {if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {throw new IllegalArgumentException("金額必須大于0");}}private void logPayment(PaymentResult result) {// 記錄支付日志}
}

方式三:優化方案 策略緩存優化

public class CachedPaymentStrategyFactory {private final Map<PaymentType, PaymentStrategy> strategyCache = new ConcurrentHashMap<>();private final List<PaymentStrategy> strategies;public CachedPaymentStrategyFactory(List<PaymentStrategy> strategies) {this.strategies = strategies;}public PaymentStrategy getStrategy(PaymentType paymentType) {return strategyCache.computeIfAbsent(paymentType, type -> strategies.stream().filter(s -> s.supports(type)).findFirst().orElseThrow(() -> new IllegalArgumentException("不支持的支付方式")));}
}

Spring相關面試題


1.Spring AOP底層實現原理是什么?
  • Spring AOP(面向切面編程)的底層實現基于動態代理技術,主要通過兩種實現方式:JDK動態代理和CGLIB字節碼生成。當目標類實現了接口,Spring默認使用了JDK動態代理,否則使用CGLIB方式,而spring-boot選擇了VCGLIB方式來實現。
    • JDK動態代理(基于接口)
      • 適用條件:目標類實現了至少一個接口
      • 代理對象通過JDK直接生成,實現目標類的接口,并通過反射調用目標類
      • 特點:
        • 運行時生成接口的代理類
        • 通過InvocationHandler攔截方法調用
        • 性能較好,但只能代理接口方法
    • CGLIB字節碼生成(基于子類)
      • 適用條件:不能使用final
      • 適用對象:目標類沒有實現接口
      • CGLIB通過CFLIB-ASM操作框架生成,繼承目標類,通過子類調用父類的方式進行調用目標方法
      • 特點:
        • 通過ASM庫直接生成目標類的子類(Enhancer)
        • 可以代理普通類方法(包括非public方法)
        • 創建代理對象速度較慢,但執行效率高
    • 代理創建流程
      • Spring AOP創建代理的核心流程:
        • 解析切面配置
        • 通過@Aspect注解或者XML配置識別切面
        • 解析切入點表達式(Pointcut)
        • 創建代理工廠(proxyFactory)
        • 選擇代理機制
        • 生成代理對象
      • JDK代理:proxy.newProxyInstance()
      • CGLIB:enhance.create()
    • 攔截器鏈執行
      • Spring AOP通過責任鏈模式執行增強邏輯
      • 增強類型與順序執行
    • spring aop支持了五種通知類型
      • @Aroud環繞通知
      • @before前置通知
      • 目標方法執行
      • @AfterReturing(返回通知,正常返回時執行)
      • @After(后置通知,finally塊中執行)
      • @AfterThrowing(異常通知,拋出異常時執行)
    • 性能優化與實現
      • Spring對AOP進行了多項優化
        • 緩沖機制
          • 代理類緩沖DefaultAopProxyFactory
          • 攔截器鏈緩沖AdvisedSupport
        • 預過濾
          • 預先排除不可能匹配的方法
          • 選擇性代理
          • 支隊匹配切入點的方法生成代理邏輯
          • 其他方法直接調用目標方法
  • 與AspectJ的關系
特性Spring AOPAspectJ
實現方式運行時動態代理編譯時/加載時織入
性能較好最優(編譯期完成)
功能范圍僅方法級別字段、構造器、靜態塊等
依賴僅Spring核心需要AspectJ編譯器/織入器
適用場景簡單切面需求復雜切面需求
  • 總結:
    • Spring AOP的底層實現本質上是基于代理模式的運行時增強,其核心特點是
      • 非侵入性:通過代理實現,不修改原始代碼
      • 靈活性:支持多種通知類型和切入點表達式
      • 可擴展性:可與AspectJ部分功能集成
      • 性能平衡:通過緩存和優化策略保證運行時效率

spring boot面試相關


1.spring boot 解決跨域5種方式

什么是跨域,當你公司的域名eg:http://mywork.com要到https://baidu.com上去獲取東西

此時可以看到域名mywork->baidu不同;協議http->https不同;端口不同;二級域名不同,ip不同等。跨域不一定有異常,跨域異常只有在前端才會發生,因為瀏覽器有一個同源策略,當發現我們不同域之間的訪問是不安全的行為,他會禁止,然后拋出異常。

  • jsonp
    • 優點是因為他夠老,能兼容各種瀏覽器,無兼容問題
    • 缺點只支持get,而且存在安全問題,且前后端都要相對應的去調整接受參數等信息。
  • cors
    • 前端不需要代碼調整,主要靠服務端進行配置,
    • cors需要瀏覽器和服務器同時支持,目前所有瀏覽器都支持該功能,IE版本不能低于10
    • 瀏覽器一旦發現AJAX請求跨源就會自動添加一些附加的頭信息,有時候還會多出一次附加的請求,但用戶不會有感知
    • ?后端使用CrossOrigin注解,配置:origins:允許的源列表、methods:允許的HTTP方法、maxAge:預檢請求緩存時間(秒)、allowedHeaders:允許的請求頭,這里只支持單獨的接口
  • 全局cors配置
    • 基于webMvcConfigure和Filter配置
  • CorsFilter 過濾器
  • nginx反向代理
  • ?Spring Security配置CORS

  • 使用Gateway統一處理(微服務架構)

方案適用場景優點缺點
@CrossOrigin簡單項目,少量端點需要跨域簡單直觀需要每個Controller單獨配置
全局WebMvc配置統一管理的中型項目一處配置,全局生效無法針對不同路徑精細控制
Filter配置需要精細控制過濾順序的項目靈活,可與其他Filter配合配置相對復雜
Spring Security已使用Spring Security的項目與安全配置統一管理需要了解Security相關知識
Gateway統一處理微服務架構,API網關統一入口前端無感知,后端統一處理需要引入Spring Cloud Gateway

mysql相關


mysql相關面試可以查看本博主其他博客:

面試題之數據庫相關-mysql篇-CSDN博客

面試題之數據庫-mysql高階及業務場景設計-CSDN博客

組合面試題


1.如何有效的阻止訂單重復提交和支付

理論上只會在用戶在下單的這個動作可能因為網絡抖動、RPC重試等進行多次下單的操作,其他步驟確認訂單只是修改訂單狀態,跳轉支付和確認支付這些不會出現多次支付的問題。所以該題主要是針對用戶多次調用下單接口怎么處理即下單接口的冪等性問題。

  • 訂單重復提交問題
    • 前端防重復提交方案
      • 按鈕置灰等操作
      • PRG模式:post/redirect/get模式,用戶點擊表單時重定向跳轉到其他頁面。
      • token機制,在用戶進入訂單界面前生成固定的token,前端限制一個token調用時,后端攔截token的一次性,做請求攔截限制
      • 請求攔截:通過axios攔截器攔截信息
    • 后端接口設計
      • 冪等性設計
        • 每次請求先配合客戶端生成一個唯一id,可由訂單id+用戶id+確認標識做綁定,同一接口,每次調用的id一致則不生成新的訂單,注意標識符的失效時間
        • 請求參數中帶有時間戳與當前時間對比,若時間太長則默認為重復請求
        • 請求狀態檢查,根據日志查詢、用戶訂單關聯查詢是否有重復數據
      • 數據庫唯一約束
        • 先獲取數據庫唯一ID來處理
      • redis原子操作
        • setnx操作,對同一個訂單id+用戶id+確認標識做綁定,設置失效時間,進行處理
  • 支付方重復方案
    • 訂單狀態機制
    • 第三方支付冪等
    • 支付結果異步核對
  • 分布式系統解決方案
    • 分布式鎖
    • 消息隊列去重
  • 異常處理機制
    • 補償事務處理
    • 人工審核接口
  • 監控與報警
    • 重復請求監控 設置ip白名單防止惡意操作
  • 建議:
    • 多層次防御:前端+后端+數據庫約束等
    • 核心原則:所有寫操作必須實現冪等性接口
    • 關鍵數據:訂單號、用戶ID、時間戳組合防重復
    • 狀態管理:嚴格的狀態機控制流程
    • 補償機制:自動核對+人工干預雙重保險
  • 技術選擇
場景推薦方案優點
簡單單體系統本地鎖+數據庫唯一約束實現簡單
分布式高并發Redis分布式鎖+消息隊列擴展性好
金融級支付系統狀態機+定時核對+人工干預可靠性最高
舊系統改造前端Token+后端冪等接口侵入性最小

2.RestTemplate 如何優化連接池
  • restTemplate默認是沒有連接池,他的調用原理是每次都會創建一個HTTP連接,默認使用simpleClientHttpRequestFactory去創建連接,底層通過HttpURLConnection創建連接。在高并發的條件下,會無上限的創建連接,消耗系統資源。所以需要通過連接池來限制最大連接數,當請求的域不是很多且不隨機的情況下,還可以復用同一個域的HTTP連接;
  • HTTP請求流程:在我們發起一個http請求連接的時候,會對域名解析,連接之前的三次握手,如果是HTTPS還需要傳遞安全證書,以及請求完成之后的4次揮手。但是我們真正請求和響應只在其中的一小環節,所以我們通過一個連接池就可以對同一個域來建立一個長鏈接,就無需執行每次的無關業務請求的動作,這樣就實現了連接的復用。
  • 通過resttemplate來配置連接池的話有HttpClient和OkHttp.
  • 具體實現:
    • 代碼上引入httpclient連接池的包,修改RestTemplate請求工廠,將默認工廠的simpleClientHttpRequestFactory換成HttpClientFactory,在為這個工廠配置請求bean。最后去設置連接池參數信息。設置最大連接數,根據QPS的響應時間平均值來設置,設置某個域的長鏈接復用,但是如果該值太小,比如設置2,那么只會創建兩個長鏈接,這樣后續的接口會進行阻塞等待。
    • 在實現連接池的方法時,需要注意以下幾點:
      • 路由區分:對重要API設置獨立的路由連接數
      • 異常處理:配置重試機制
      • DNS刷新:避免DNS緩沖問題
      • 連接存活時間
參數建議值說明
setMaxTotal100-500最大連接數,根據服務器配置調整
setDefaultMaxPerRoute50-100每個路由(host:port)的最大連接數
setConnectTimeout3000-5000ms建立TCP連接的超時時間
setSocketTimeout5000-10000ms數據傳輸超時時間
setConnectionRequestTimeout1000-2000ms從連接池獲取連接的超時時間
evictIdleConnections30-60s空閑連接回收時間

3.如何設計秒殺系統?高并發?

查看此博客:面試題之如何設計一個秒殺系統?-CSDN博客

工具類應用


1.git如何撤回已提交的push代碼

使用idea集成可視化界面操作

  • 已提交 未推送
    • 使用idea,找到提交的版本,選擇undo commit
  • 已提交 已推送
    • revert commit->本地代碼回滾到提交前的版本->在push一下 將遠程倉庫代碼覆蓋上
  • 已回滾 代碼恢復
    • 選擇剛才已經回滾的代碼->cherry pick還原已經寫好的代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79847.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79847.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79847.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL】Read view存儲的機制,記錄可見分析

read view核心組成 1.1 事務id相關 creator_trx_id: 創建該read view的事務id 每開啟一個事務都會生成一個 ReadView&#xff0c;而 creator_trx_id 就是這個開啟的事務的 id。 m_ids: 創建read view時系統的活躍事務&#xff08;未提交的事務&#xff09;id集合 當前有哪些事…

【刷題Day20】TCP和UDP(淺)

TCP 和 UDP 有什么區別&#xff1f; TCP提供了可靠、面向連接的傳輸&#xff0c;適用于需要數據完整性和順序的場景。 UDP提供了更輕量、面向報文的傳輸&#xff0c;適用于實時性要求高的場景。 特性TCPUDP連接方式面向連接無連接可靠性提供可靠性&#xff0c;保證數據按順序…

Flink 內部通信底層原理

Flink 集群內部節點之間的通信是用 Akka 實現,比如 JobManager 和 TaskManager 之間的通信。而 operator 之間的數據傳輸是用 Netty 實現。 RPC 框架是 Flink 任務運行的基礎,Flink 整個 RPC 框架基于 Akka 實現。 一、相關概念 RPC(Remote Procedure Call) 概念 定義:…

企業級Kubernetes 1.28高可用集群離線部署全指南(含全組件配置)

企業級Kubernetes 1.28高可用集群離線部署全指南(含全組件配置) 摘要:本文手把手教學在無外網環境下部署生產級Kubernetes 1.28高可用集群,涵蓋ETCD集群、HAProxy+Keepalived負載均衡、Containerd運行時、Calico網絡插件及Kuboard可視化管理全流程。提供100年有效證書配置…

【中間件】redis使用

一、redis介紹 redis是一種NoSQL類型的數據庫&#xff0c;其數據存儲在內存中&#xff0c;因此其數據查詢效率很高&#xff0c;很快。常被用作數據緩存&#xff0c;分布式鎖 等。SpringBoot集成了Redis&#xff0c;可查看開發文檔Redis開發文檔。Redis有自己的可視化工具Redis …

C語言——函數遞歸與迭代

各位CSDN的uu們大家好呀&#xff0c;今天將會給大家帶來關于C語言的函數遞歸的知識&#xff0c;這一塊知識理解起來稍微會比較難&#xff0c;需要多花點時間。 話不多說&#xff0c;讓我們開始今天的內容吧&#xff01; 目錄 1.函數遞歸 1.1 什么是遞歸&#xff1f; 1.2 遞歸…

藏品館管理系統

藏品館管理系統 項目簡介 這是一個基于 PHP 開發的藏品館管理系統&#xff0c;實現了藏品管理、用戶管理等功能。 藏品館管理系統 系統架構 開發語言&#xff1a;PHP數據庫&#xff1a;MySQL前端框架&#xff1a;BootstrapJavaScript 庫&#xff1a;jQuery 目錄結構 book/…

centos停服 遷移centos7.3系統到新搭建的openEuler

背景 最近在做的事&#xff0c;簡單來講&#xff0c;就是一套系統差不多有10多臺虛擬機&#xff0c;都是centos系統&#xff0c;版本主要是7.3、7.6、7.9&#xff0c;現在centos停止維護了&#xff0c;轉為了centos stream&#xff0c;而centos stream的定位是&#xff1a;Red …

什么是 IDE?集成開發環境的功能與優勢

原文&#xff1a;什么是 IDE&#xff1f;集成開發環境的功能與優勢 | w3cschool筆記 &#xff08;注意&#xff1a;此為科普文章&#xff0c;請勿標記為付費文章&#xff01;且此文章并非我原創&#xff0c;不要標記為付費&#xff01;&#xff09; IDE 是什么&#xff1f; …

jenkins批量復制Job項目的shell腳本實現

背景 現在需要將“測試” 目錄中的所有job全部復制到 一個新目錄中 test2。可以結合jenkins提供的apilinux shell 進行實現。 測試目錄的實際文件夾名稱是 test。 腳本運行效果如下&#xff1a; [qdevsom5f-dev-hhyl shekk]$ ./copy_jenkins_job.sh 創建文件夾 test2 獲取源…

VisualSVN過期后的解決方法

作為一款不錯的源代碼管理軟件&#xff0c;svn還是有很多公司使用的。在vs中使用svn&#xff0c;大家一般用的都是VisualSVN插件。在30天試用期過后&#xff0c;它就不能被免費使用了。下面給大家講如何免費延長過期時間&#xff08;自定義天數&#xff0c;可以設定一個很大的值…

硬件工程師筆記——電子器件匯總大全

目錄 1、電阻 工作原理 歐姆定律 電阻的物理本質 一、限制電流 二、分壓作用 三、消耗電能&#xff08;將電能轉化為熱能&#xff09; 2、壓敏電阻 伏安特性 1. 過壓保護 2. 電壓調節 3. 浪涌吸收 4. 消噪與消火花 5. 高頻應用 3、電容 工作原理 &#xff08;…

[圖論]Kruskal

Kruskal 本質&#xff1a;貪心&#xff0c;對邊進行操作。存儲結構&#xff1a;邊集數組。適用對象&#xff1a;可為負權圖&#xff0c;可求最大生成樹。核心思想&#xff1a;最短的邊一定在最小生成樹(MST)上&#xff0c;對最短的邊進行貪心。算法流程&#xff1a;對全體邊集…

vulnhub five86系列靶機合集

five86 ~ VulnHubhttps://www.vulnhub.com/series/five86,272/ five86-1滲透過程 信息收集 # 主機發現 nmap 192.168.56.0/24 -Pn ? # 靶機全面掃描 nmap 192.168.56.131 -A -T4 目錄掃描 dirsearch -u http://192.168.56.131/ /robots.txt提示/ona。 /ona二層目錄掃描。 …

如何高效利用呼叫中心系統和AI語音機器人

要更好地使用呼叫中心系統和語音機器人&#xff0c;需要結合兩者的優勢&#xff0c;實現自動化、智能化、高效率的客戶服務與業務運營。以下是優化策略和具體實踐方法&#xff1a; 一、呼叫中心系統優化 1. 智能路由與IVR優化 智能ACD&#xff08;自動呼叫分配&#xff09; …

Nacos安裝及數據持久化

1.Nacos安裝及數據持久化 1.1下載nacos 下載地址&#xff1a;https://nacos.io/download/nacos-server/ 不用安裝&#xff0c;直接解壓縮即可。 1.2配置文件增加jdk環境和修改單機啟動standalone 找到bin目錄下的startup.cmd文件&#xff0c;添加以下語句(jdk路徑根據自己…

【牛客練習賽137 C】題解

比賽鏈接 C. 變化的數組(Easy Version) 題目大意 一個長度為 n n n 的非負數組 a a a&#xff0c;要求執行 k k k 次操作&#xff0c;每次操作如下&#xff1a; 有 1 2 \frac{1}{2} 21? 的概率令 a i ← a i ( a i ? m ) x , ? i ∈ [ 1 , n ] a_i \leftarrow a_…

Redis適用場景

Redis適用場景 一、加速緩存二、會話管理三、排行榜和計數器四、消息隊列五、實時分析六、分布式鎖七、地理位置數據八、限流九、數據共享十、簽到 一、加速緩存 Redis最常見的應用之一是作為緩存層&#xff0c;用于存儲頻繁訪問的數據&#xff0c;從而減輕數據庫的負載。 通過…

【LangChain4j快速入門】5分鐘用Java接入AI大模型,Spring Boot整合實戰!| 附源碼

【LangChain4j快速入門】5分鐘用Java接入AI大模型&#xff0c;Spring Boot整合實戰&#xff01; 前言&#xff1a;當Java遇上大模型 在AI浪潮席卷全球的今天&#xff0c;Java開發者如何快速擁抱大語言模型&#xff1f;LangChain4j作為專為Java打造的AI開發框架&#xff0c;以…

2025第十七屆“華中杯”大學生數學建模挑戰賽題目B 題 校園共享單車的調度與維護問題完整成品正文33頁(不含附錄)文章思路 模型 代碼 結果分享

校園共享單車運營優化與調度模型研究 摘 要 本研究聚焦校園共享單車點位布局、供需平衡、運營效率及故障車輛回收四大核心問題&#xff0c;通過構建一系列數學模型&#xff0c;系統分析與優化共享單車的運維體系。 針對問題一&#xff0c;我們建立了基于多時段觀測的庫存估算…