面试题之高频面试题

最近开始面试了,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.mzph.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;我们建立了基于多时段观测的库存估算…