ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Spring 面经系列 · 第 9 篇(收官):跨域、防盗链、配置写法、并发容量与事件机制

Spring 面经系列 · 第 9 篇(收官):跨域、防盗链、配置写法、并发容量与事件机制 Spring 面经系列 · 第 9 篇收官跨域与防盗链、配置写法、容量并发、批量插入、事件机制与源码设计模式前面八篇走完了 Spring 主干Bean 生命周期、循环依赖、容器扩展点、AOP、事务、MVC、Spring Boot、微服务。这一篇收剩下的八道题它们有个共同特征——不是纯八股面试官问它们时手里拿的是你的项目简历。「前端调接口跨域怎么办」「防盗链做过吗」「100 万条数据怎么导」「你这服务能同时扛多少请求」「Controller是单例并发怎么处理」「读配置有几种写法」「事件监听用过吗」「源码里有哪些设计模式」——这八问的杀伤力不在知识点而在它逼你给出具体数字、具体类名、具体取舍。说「用 CORS 就行」和「我用 Nginx 反代因为要兼容老浏览器」是两个层次报「8192」和「8192 是连接上限真正并行的是 200 个线程瓶颈在数据库连接池」也是两个层次。素材是 P07、P08、P10、P11、P13、P16、P41、P42 八个分 P。凡视频给的具体数字我一律标注「视频口述未复现」。1. 跨域与防盗链一个管浏览器放行一个管资源访问这两件事常被并成一句回答其实不在同一层。跨域CORS -- 浏览器同源策略 -- 决定「谁家前端能读到我给的响应」 -- 服务端只负责把响应头写对 防盗链 -- 服务端资源访问控制 -- 决定「谁在拿我的资源」 -- 需要真的拦下来1.1 先钉死「跨域只发生在浏览器」同源比协议、域名、端口作者补了二级域名不同、IP 不同也算跨域。值得记的是那个反问跨域一定有异常吗不一定。异常只在前端发生因为浏览器有同源策略后端RestTemplate请求别的域也是跨域但不报错——没有浏览器就没人执行这条规矩。推出来的结论就是两者的分界线服务端配 CORS 只是「给浏览器一个放行凭据」对 curl、爬虫、服务器间调用完全无效。想白嫖资源的人根本不看你的响应头。所以「配了 CORS 就等于安全」是错的作者也因此把防盗链单独做成了一题。1.2 五种方式与各自的边界方式写法要点视频口径生效层限制与坑什么时候真用JSONP前端dataType指定 jsonp自动带一个随机值的callback后端声明同名参数接住返回callback(数据)拼成的格式前后端都写只支持 GET参数名两端耦合改一处改两边只剩维护上古系统作者明确它已被 CORS 替代CrossOrigin打在某个 Controller 或方法上后端注解一接口一注解量大了铺不开只开放一两个接口WebMvcConfigurer重写「添加跨域映射」那个方法用注册器按路径前缀批量放行后端配置类全局配置类容易膨胀一批接口统一放行CorsFilter注册一个CorsFilterBean过滤器层与其他 Filter 的先后顺序会影响结果想在入口层全量解决Nginx 反向代理前端站由 Nginx 起举例 8081带约定前缀如/cors的请求转到后端 8080接入层换部署拓扑要重配本地开发得靠 devServer 代理作者最推荐前后端代码零改动浏览器侧还有个细节复杂请求会被请求两次。浏览器一旦发现跨域就自动附加请求头复杂请求先发的第一次是OPTIONS探后端支不支持第二次才真正带参。视频强调这套「由浏览器决定」因此依赖浏览器版本支持作者口径是 IE 不低于 10兼容矩阵未核实。再补一个真会被追问的坑这条我核过源码带 Cookie 时要设allowCredentialstrue此时allowedOrigins不能写*——CorsConfiguration直接抛IllegalArgumentException得显式列 origins 或改用allowedOriginPatterns。「来源全开 允许凭证」这个看着最省事的配法在框架层根本不成立。Q1跨域和防盗链是同一件事的两种说法吗不是判定方向还是反的。CORS 是默认禁止、显式放行不在白名单响应照样发回去只是浏览器拒绝交给 JS 读防盗链是默认允许、主动拦截服务端自己判来源、身份或时间判不过就 403。两者甚至会互相拆台——我见过服务端校验Referer白名单却没写自家前端域名跨域通了、资源全 403。工程上比较稳的分工是跨域放接入层访问控制靠鉴权、签名与时效。1.3 三种防盗链本质都是「提高破解成本」作者的场景很直白数据是网站的核心竞争力爬虫偷资源既压服务器又损利益。他也给了这篇最清醒的一句「哪怕你再怎么防也只能增加破解的难度」——只要数据能被正常访问攻击者就能伪装成正常用户。手段判定依据实现位置作者给的绕过方式Referer 校验请求头Referer是否在允许来源不在直接拒Nginx 校验或 Boot 里声明一个过滤器取头判断直接伪造RefererToken 校验登录后下发 token转写作 “GWT”疑为 JWT未核实每次携带缺失或校验失败即拒后端拦截器攻击者打登录接口拿 token 再带上时间校验响应时给前端埋时间戳请求回来算差值作者口径是「停留超过允许时长举例 300ms判为正常否则视为盗链」前端埋点 后端算差值每次伪造请求前sleep一秒共性是单点必破所以作者的落点有两处值得记时间校验一定有误判要叠加拖动验证码让人证明是真人大厂再叠一层行为风控——用大数据分析行为异常沉淀成黑名单每次请求过滤。合起来就是防盗链的真实定位分层叠加 持续对抗没有银弹。300ms 那个阈值方向在转写里含糊我按「间隔过短判为机器」理解属笔者判断。2. 读配置的六种写法只谈写法与选型加载原理与优先级在 第 7 篇 §7 讲过这里不重复。这题问的是另一个层面同一个 key 落到代码里有六种写法。#写法粒度前提与坑典型场景1Value(${xxx.name})单个 key所在类必须是 Bean配置里必须有这个 key否则启动报错故要给默认值${a:b}static/final不生效视频口径一两个开关、阈值2ConfigurationProperties(prefixxxx)前缀下整棵子树需可绑定的属性结构批量绑定作者原话一二十个字段不用写一二十个注解3注入Environment调getProperty运行时任意 key它本身就是 Bean直接装配运行时决定作者举例配一个目标 class 加isEnable动态控制某个 Bean 是否生效4实现EnvironmentAware#setEnvironment同上容器回调赋值不靠注入写组件的人自定义 starter、自动配置类里取底层 Bean作者说「耦合更低」5PropertySourceValue自定义外部文件作者明确这注解只吃.properties要读 YAML 得配PropertySourcesPlaceholderConfigurerBean往里放YamlPropertiesFactoryBean指定外部 YAML全局配置之外还有独立文件6JDKPropertiesInputStream任意文件与 Spring 无关无占位符无 profile工具类、单测、容器还没起来的早期作者的选型一句可用前三种最实用后三种都是「读外部自定义文件」才动。我再加一条新业务配置一律走ConfigurationProperties成组、可校验、IDE 能提示Value只留零散项。最容易出事故的是写法 1 的两个静默失效——类不是 Bean自己new的、字段是static配置就是注不进去且不提示。3. 容量题Spring Boot 可以同时处理多少请求作者开场就承认这题有歧义这个判断对。歧义在「同时处理」指哪个数能被接受的连接数 -- maxConnections店里能坐多少桌 真正并行执行的 -- maxThreads几个厨师同时在炒 一秒吃下的请求 -- QPS 并发数 / 平均耗时出菜速度3.1 四个参数与带版本的默认值视频的比喻很好背Web 服务器是饭店线程是厨师正式 兼职连接数是店里能坐的桌数等待数是门口能排的队伍。参数Boot 属性名Tomcat 属性官方默认值饭店比喻最大线程数server.tomcat.threads.maxmaxThreads200正式兼职总数真正「同时处理」的量最小空闲线程server.tomcat.threads.min-spareminSpareThreads10常驻正式员工最大连接数server.tomcat.max-connectionsmaxConnections8192店里能坐的桌数最大等待数server.tomcat.accept-countacceptCount100门口能排多少队连接超时server.tomcat.connection-timeoutconnectionTimeout文档 60000ms发行版server.xml写 20000ms排队者的耐心默认值不是我的印象是查的Tomcat 9.0 与 Tomcat 10.1 的 Connector 文档四条一致Spring Boot 2.7 属性附录 同值。报数带版本是这题的基本礼貌。一条请求的判定顺序请求到达 -- ① 连接数 maxConnections 否 -- OS 队列(acceptCount)再不满直接拒 ↓ 是 ② 有空闲线程minSpare 都忙则扩到 maxThreads -- ③ 不够则进线程池队列 -- ④ 耐心用完 -- connect timeout3.2 视频的答案和我的不同意见视频的答法是从 Spring 的配置元数据 JSON 里查默认值得maxConnections8192、acceptCount100于是「8192 100 8292就是这题的答案」。查元数据这个动作值得学但算法口径我不认同8292 是「被接受 排队」的连接总量不是「同时处理」同一刻真正在跑业务的线程最多只有 200。只报 8292被追一句「那你的 200 个线程在干什么」就露馅。作者随后压了一轮视频口述未复现演示配maxConnections30、acceptCount10、maxThreads20、minThreads10接口sleep2 秒压测线程 100另配连接超时 300ms结果 140 请求里 40 成功、60 失败异常率 60%。这组数字正好把四参数演完100 请求 -- 30 桌 10 队 40 被接住 -- 其余 60 耐心只有 300ms、业务要 2s -- 全超时 40 里真正并行是 20 个线程 -- 另 20 个进线程池队列等前一个炒完他的收尾意见很实在这几个参数在高并发应用里肯定要调但要「结合硬件性能、网络 IO 模型、实际压测与监控」才能定最优。Q2那这题面试里到底怎么答三步。先纠口径三个概念不是一回事再带版本报默认值Tomcat NIO 连接器maxConnections8192、acceptCount100、maxThreads200、minSpareThreads10所以理论并行度是 200最后给真正的算法并发 ≈ QPS × 平均响应时间一个 200 线程、单请求 100ms 的服务理论吞吐就在 2000 QPS 附近而实际瓶颈通常在下游数据库连接池、远程调用、GC。收尾一句「我们项目实测是……」比背 8292 有效。至于参数怎么调到最优我的态度和作者一致点到为止比硬讲 IO 模型安全。4. 线程并发Bean 那半在第 1 篇这半讲处理链路分工先说清第 1 篇 §6 讲「单例 Bean 的字段怎么被并发读写」第 6 篇 §2 讲「控制器单例的状态问题」。P16 是紧接着追问下来的——除了把成员变量挪进方法还有什么办法视频给了四种我按代价排方案做法为什么就安全了代价消灭状态变量只声明在方法里每线程一个栈帧无共享几乎为零首选换多例Scope(prototype)线程一、二各拿一个新实例操作自己那份每次走完整创建链、容器不留引用被单例持有则等于白配ThreadLocal字段包成ThreadLocalset赋get取两条线程虽共用同一个单例但值绑在各自线程上必须清理线程池复用会串数据同步锁synchronized方法或代码块线程二被挡在外面等前者return释放锁才进并行变串行影响吞吐量视频原话要记的是这四种解法暴露的判断力多例把并发压力换成了创建开销同步锁把接口吞吐手动砍成 1。4.1 线程和状态在哪儿相遇这题的深度在这张图Tomcat worker 线程 -- Filter -- DispatcherServlet -- Controller单例 -- Service单例 -- JDBC / 远程调用 一条请求 一条线程从头走到尾同步阻塞模型单例 Controller/Service 是全进程共享的协作者而请求级状态本来就该住在每请求一条线程上。所以 Spring 自己就是ThreadLocal的重度用户请求上下文RequestContextHolder第 6 篇点过、事务与那条连接的复用TransactionSynchronizationManager第 5 篇 §5、语言区域LocaleContextHolder、AOP 暴露的当前代理exposeProxy第 4 篇。一句话理解框架用线程隔离的上下文放请求级状态用无状态 Bean 放协作者两者配合才让单例 Bean 在高并发下成立。这才是「Spring 怎么处理并发」的答案。4.2 ThreadLocal 的两条风险线一是泄漏与脏读。线程池里线程不销毁跑完一个任务接着跑下一个上一次的 value 还挂在ThreadLocalMap上既占内存连带其引用的对象图又能被下个请求读到。JDK 17 文档 能核到的表述是「线程消失后它的 thread-local 副本才会被回收除非还有其他引用」——反过来说线程不死清理只能靠你。写法没得商量try { ... } finally { HOLDER.remove(); }或者别自己造用框架给好的上下文。二是异步链路踩空。Async方法、DeferredResult、自己提交进线程池的任务都跑在另一条线程上前面那套上下文一律拿不到。这个坑我在SimpleApplicationEventMulticaster的 javadoc 里看到同一逻辑的官方表述设了异步 executor 后调用方不再阻塞但异步执行不带调用线程的事务、类加载器等上下文除非 executor 支持。解法是把数据当参数传或用TaskDecorator复制上下文ThreadPoolTaskExecutor确有这个字段其余未逐行核对。5. 工程性能线程池把 100 万条插入从 90 秒压到 17 秒P08 全程在给数字均为视频口述笔者未复现做法关键配置视频里的耗时单线程循环批量插 100 万无并发90 多秒接近 100切 100 份 × 每份 1 万逐份异步批量保存线程池核心 32 / 最大 6616 核17 秒左右继续加线程核心 100 / 最大 20016 秒几乎没变第三步才是重点作者结论一句可背「线程并不是越多越好改善不大反而浪费资源这些资源该留给别的业务」。5.1 抽成可复用套路造数/读源 -- 切片每片 1 万 -- 线程池逐片提交 -- 每片一次批量写 countDown -- latch.await() 收口 -- 统计耗时切片大小一片对应一次批量写。太大容易撞报文长度限制和长事务max_allowed_packet的具体值未核实太小则网络往返占大头。用CountDownLatch收口计数等于片数这里是 100每份保存完countDown()主线程await()到全部异步线程跑完再统计耗时。我补一句await()不配超时一个卡死的任务会让主线程永远挂着。线程数按任务性质定作者先分两类——IO 密集读文件、走网络会阻塞、CPU 反而闲与 CPU 密集数据处理、排序、分析CPU 满载并判定操作数据库是 IO 密集于是核心线程按核数 ×2他补 1 是「防不可预料的阻塞时 CPU 能切给多余线程」16 核给 32/33。他讲最大线程数时前后不一先说四倍又说「也就是核心的两倍66」我按 66 理解成 2 倍加余量这类公式在面试里说「按任务类型定、压测收口」更稳。Async要配自定义线程池作者口径是「Async默认不推荐直接用但在 Boot 里太方便只要把自定义线程池 Bean 设成它用的线程池就没问题」。他还点了ThreadPoolTaskExecutor与 JDKThreadPoolExecutor的区别核心数、最大数、阻塞队列、空闲等待、拒绝策略都有额外能给每个线程设名字前缀——排线上堆栈时这条特别值。5.2 它和事务一致性是什么关系这段必须主动交代。任务丢进线程池后执行线程变了事务上下文就断了这 100 份是 100 个互不相干的事务完全可能 99 份成功、1 份失败。多线程事务为什么保不了一致、那「两句代码」的解法第 5 篇 §7 已成篇P39、P03不重复。所以套路的定位要说准它适合初始化导数、离线灌数据、报表落库这类「能重跑」的任务不适合业务写单。真要在业务里并发写得配三件事——每片幂等重跑不产生重复、失败记录与重试、断点续跑或者让一片要么全成要么全败靠重跑收敛。别指望线程池替你保住 ACID。Q3为什么开到 100、200 反而不比 32 快因为收益来源不是线程数而是把串行等待的 IO 时间重叠掉。100 份数据、32 并发已经把网络和磁盘等待填满再加线程只是让更多线程一起去堵同一个瓶颈——数据库连接池上限、单条 INSERT 还是 multi-values、MySQL 服务端的日志与索引维护。前 32 个是重叠等待后面的是排队等待切换开销和锁竞争还往上加。笔者补一条常被拿来同类优化的项Connector/J 的rewriteBatchedStatements视频没提默认值与效果未从官方文档核实。作者的落点是对的参数靠压测加上线后监控来定大项目还要上动态线程池——参数改了不可能重启而线上线程池的使用情况对程序员是黑盒得在用量触阈值时告警下发那套可看 第 8 篇的配置中心如 Nacos。6. Spring 事件机制进程内解耦的那一档作者开场替读者说了实话大部分同学不知道事件监听因为学 Spring 时不讲、写代码也很少用。但它源码里出现频率极高——视频原话是Spring 集成其他框架大量用事件监听做扩展Boot 和各微服务组件都靠它看源码绕不过。6.1 三件套与观察者角色映射组成你要写的观察者模式里的角色事件Event继承ApplicationEvent或直接用内置的被发布出来的通知监听器Listenerimplements ApplicationListenerXxxEvent或方法标EventListener观察者发布者Publisher容器已建好业务侧调publishEvent()被观察者 分发器ApplicationEventMulticaster业务的例子是「下单后减库存」想把减库存和下单解耦就发一个下单事件监听器做后续。作者的用途判断也直白——就是给业务之间解耦顺带提高可扩展性与可维护性。发布路径可以画成一条链publishEvent(event) -- SimpleApplicationEventMulticaster.multicastEvent -- 按事件类型筛监听器 -- 依次 onApplicationEvent默认在调用线程同步跑完除了自己发容器在 IOC 加载的多个位置已替我们发好了。视频给的数字是「内置五个事件」点名了上下文刷新完毕、启动、停止、关闭以及请求处理那一类想在容器 refresh 完成后扩展监听对应事件就行——跟第 3 篇 §5 里ContextRefreshedEvent那个收尾扩展点是同一件事数量与类名清单我未逐一对照 API 核数。6.2 同步是默认异步有两条路最容易答错的就是这点。视频表述很准事件默认同步发布——你在这里发事件必须等监听器代码执行完发布点后面的语句才继续。这点在SimpleApplicationEventMulticaster的 javadoc 里能对上默认所有监听器在调用线程里被调用好处是开销小风险是「一个失控的监听器可能堵住整个应用」。同一个 javadoc 还给了常被忽略的一条异常处理器默认是 none监听器抛异常会中断本次广播并抛回发布者——所以监听器里必须自己兜异常。改成异步视频给两条路给监听加注解或给分发器设一个TaskExecutor——底层判断到你配了 executor就用它起子线程执行监听器这就是「异步事件发布的核心机制是多线程」。要注意的正是 §4.2 那句一旦异步监听器就不在调用线程的事务上下文里了。事务绑定事件视频未展开实践最有用的一块我核过 javadocTransactionalEventListener默认阶段是AFTER_COMMIT等事务提交后才触发fallbackExecution默认false当前没有事务在跑就把事件丢掉——线上最常见的一类静默失效就是它。更要紧的是那段警告AFTER_COMMIT/AFTER_ROLLBACK/AFTER_COMPLETION阶段事务已提交或回滚但事务资源可能仍活跃此时在监听器里继续写库改动不会被提交要接着落库得另起事务REQUIRES_NEW或走异步。Q4事件监听能替掉 MQ 吗作者取舍很务实小型应用用事件解耦「大一点的应用一般用 MQ 替代事件监听」因为分布式场景下 MQ 性能和能力都更合适。我把「不能替」写成三条① 事件只在当前进程内传多实例部署时另一个实例根本收不到② 没有持久化和重试进程一重启还没跑的监听逻辑就没了③ 没有削峰同步模式下发布者线程直接承担监听器耗时。反过来它的价值也明确零外部依赖不必为「下单成功后干点啥」引入 Kafka/RocketMQ 一整套集群、天然贴着事务边界、以及它是 Spring 生态自己扩展自己的方式。判断标准一句同进程、允许一起挂 → 事件跨进程、要求不丢 → MQ。7. 源码里的设计模式十个但别说十个作者的开场条件是「你简历写了熟读 Spring 源码」这题就跑不掉。他说整理了十个并给出体现位置转写里能确认的落点我列全模式视频给的落点我的口径与核实状态简单工厂BeanFactory类名可核按 beanName 定义产出实例「它就是简单工厂」属模式归类是口径工厂方法FactoryBean类名可核容器给外部的是getObject()的产物而非工厂单例单例 Bean / 单例池第 1 篇 §4 已辨析这是容器管的单例不是 GoF 单例模式别混着答代理AOP 底层JDK 动态代理 / CGLIB代理在哪一步创建见 第 4 篇 §5观察者事件监听就是本篇 §6 那三个角色能连起来讲最好模板方法「几乎所有外接扩展」各类后置处理器refresh()里一串doXxx、BeanPostProcessor前后两段第 1、3 篇画过标签是视频口径责任链AOP 的方法调用过程拦截器链依次往下调第 4 篇 §6 那条链是否严格算责任链是笔者判断适配器Spring MVC作者还没看 MVC 源码可以先不说常指HandlerAdapter——视频中提到笔者未对照源码核实装饰器BeanWrapper视频中提到笔者未对照源码核实策略把配置类注册成BeanDefinition时用的excludeFilters/includeFilters转写作 exclude field体现不同导入导出策略视频中提到笔者未对照源码核实这两个数组与FilterType确实存在归类按视频口径作者的答题策略建议照搬记住五六个就够——工厂、单例、代理、观察者、责任链这五个基本白捡模板方法属于「任何框架都用了无脑答」真把十个背满「面试官已经没耐心听下去了」。我和他的用法略有不同这题的加分点是模式 具体类名 它解决了什么这三件套。讲清两个FactoryBean解决「实例化过程要我自己控制」SimpleApplicationEventMulticaster解决「发布方与订阅方互不知晓」比报十个名字有效。本文覆盖分 P分 P视频原始标题本文对应小节P07SpringBoot防盗链的3种方式1.3三种手段与「只能增加破解难度」P08springboot线程池百万数据插入5三段耗时、切片 线程池 CountDownLatch套路P10SpringBoot解决跨域的5种方式1.1、1.2五种方式对照表、预检与浏览器限制P11SpringBoot读配置的6种方式2六种写法对照表与选型P13SpringBoot可以同时处理多少请求3四参数默认值、饭店比喻、8292 的口径争议P16Spring如何处理线程并发问题4四种解法 链路上的 ThreadLocal、泄漏与异步P41Spring事件监听的核心机制是什么6三件套、同步默认、异步两条路、事务绑定P42Spring源码用到了哪些设计模式7十个模式对照表与答题策略最后总结这八题串起来是同一类问题面试官在验证你有没有把框架放进真实流量里跑过。我的判断分四层。第一跨域与防盗链必须一起讲跨域是浏览器的规矩、服务端只是配合防盗链是服务端的判定、得自己拦。五种跨域里真正只剩两条能用——CorsFilter/WebMvcConfigurer管开发期Nginx 反代管部署期JSONP 是历史。第二容量题和并发题都埋着口径陷阱。8292 是连接数不是并发数同步锁是安全但不是方案能立住的表达是并行度看maxThreads容量看 QPS × RT瓶颈看下游以及Spring 靠「无状态 Bean 线程隔离上下文」支撑并发你写的 ThreadLocal 只在同一线程内成立异步一律踩空。第三性能类题目必须答成「数字 归因 收口方式」。17 秒比 90 秒快靠的是重叠 IO 等待不是线程多归因讲清了作者那句「参数要靠压测和监控定、大项目上动态线程池」才不是套话。批量插入还要补一条边界它是能重跑的任务不是能保整体一致的业务写单——主动交代事务边界比等追问好。第四P41、P42 是源码收尾。事件机制一句话同进程、允许丢、零依赖 → 事件跨进程、不能丢、要削峰 → MQ。设计模式别贪多能连着类名讲两三个比背十个名字更像看过源码的人。事实说明视频里给的事实只代表转写表述错字我已按书面术语修正跨域异常只在前端发生后端RestTemplate/HTTP client 请求别的域不报错五种方案为 JSONP只支持 GET、两端耦合、CrossOrigin单接口、WebMvcConfigurer按前缀批量、CorsFilter全量、Nginx 反代作者最推荐前后端零改动复杂请求先OPTIONS预检、可能请求两次且需浏览器版本支持举例 IE 不低于 10。三种防盗链为 RefererNginx 或过滤器校验可伪造、Token登录下发可合法获取后携带、时间戳差值举例 300ms可被「请求前睡一秒」绕过并建议叠加拖动验证码、大厂再叠行为分析与黑名单。读配置六写法为Value、ConfigurationProperties、注入Environment、EnvironmentAware、PropertySource作者称只吃 propertiesYAML 需PropertySourcesPlaceholderConfigurerYamlPropertiesFactoryBean、JDKProperties手读流结论是前三种最实用Value须是 Bean、key 缺失启动报错、static/final 不生效。容量题饭店比喻与四参数含义演示配置 30/10/20/10、超时 300ms、sleep 2s、压测 100 得 40 成功 60 失败查元数据得默认值 8192 100 8292。并发题局部变量、prototype、ThreadLocal、synchronized四种解法作者明确最后一种影响吞吐。批量插入90 多秒 → 切 100 份 × 1 万 线程池核心 32/最大 66CountDownLatch→ 17 秒 → 核心 100/最大 200 → 16 秒Async默认不推荐直接用、需自定义线程池 BeanThreadPoolTaskExecutor比 JDK 的多线程名前缀IO 密集可核数 ×21 兜底后续靠压测、监控与动态线程池。事件监听三部分为事件、监听器、发布者核心机制是观察者模式内置约五个事件默认同步阻塞异步靠加注解或给分发器配TaskExecutor小应用用事件、大应用用 MQ。设计模式整理十个转写能确认的落点见 §7 表建议答五六个即可。官方文档 / 公开事实本次亲自核实链接见文末① Tomcat 9.0 与 Tomcat 10.1 的 Connector 文档NIO 连接器默认maxThreads200、minSpareThreads10、acceptCount100、maxConnections8192connectionTimeout文档默认 60000ms发行版server.xml写 20000ms达到maxConnections后「接受但不处理」再一个连接、之后由 OS 按acceptCount排队② Spring Boot 2.7.18 属性附录 中对应四项同值③ Spring Framework APIcurrent页面显示 7.0.9的SimpleApplicationEventMulticaster默认在调用线程通知所有监听器原文警告失控监听器可堵住应用setTaskExecutor可改异步、但异步执行不参与调用线程的事务/类加载上下文ErrorHandler默认 none、监听器异常中断本次广播并抛给发布者④ 同版本TransactionalEventListenerphase默认AFTER_COMMITfallbackExecution默认false无事务时事件被丢弃并警告此阶段继续写库的改动不会被提交⑤ v6.1.14 源码ThreadPoolTaskExecutorcorePoolSize1、maxPoolSizeInteger.MAX_VALUE、keepAliveSeconds60、queueCapacityInteger.MAX_VALUEqueueCapacity0时用SynchronousQueue有taskDecorator字段⑥ 同 tag 源码CorsConfigurationallowCredentialstrue且allowedOrigins含*时抛IllegalArgumentException并提示改用allowedOriginPatterns⑦ JDK 17ThreadLocalAPI线程消失后其 thread-local 副本才可被回收除非存在其他引用。源码原文因raw.githubusercontent.com连接被重置改由 jsDelivr 的 GitHub 镜像按同一 tag 拉取。笔者判断 / 未核实① 「8292 是本题答案」是视频口径我判定它混淆连接上限与并行度该反驳属笔者判断② P13 的 40 成功/60 失败/异常率 60%以及 P08 的 90 多秒/17 秒/16 秒与 32、66、100、200 这些线程数全是视频口述、未复现的观察值不构成性能结论③ 压测工具转写作 “g matter”我按 JMeter 理解属推测④ 「CORS 需 IE10 及以上」的兼容矩阵、Nginx 校验 Referer 的指令名与写法、max_allowed_packet默认值均未核实⑤ 时间戳防盗链 300ms 的阈值方向在转写里含糊我按「间隔过短判为机器」理解改用服务端下发带时效的一次性签名属笔者建议⑥PropertySource只支持 properties、YAML 必须靠YamlPropertiesFactoryBean是视频口径Value在 static/final 上失效的确切成因、ConfigurationProperties需要哪些开启方式如EnableConfigurationProperties未核对⑦Async未指定 executor 时底层退化成什么执行器我没核到源码v6.1.14 里该类父类文件的路径与我尝试的不一致故只转述作者的「默认不推荐直接用」Boot 自动配置那个线程池的默认参数也未核实⑧ThreadLocalMap「弱键强值」这条常见表述我只核到 JDK 文档「线程消失后才回收」那句Entry 引用强度未看源码⑨ MySQL 的rewriteBatchedStatements、以及数据库连接池上限如 HikariCPmaximumPoolSize会卡住并发写都是笔者补充默认值与效果未从官方文档核实⑩ 「200 线程 × 100ms ≈ 2000 QPS」是我给的分析框架视频没有且假设了纯阻塞、无下游瓶颈⑪ P41「内置五个事件」的确切数量与类名清单、以及 Boot/Spring Cloud 各组件靠事件集成的具体落点未逐一对照源码⑫ P42 表中标「视频中提到笔者未对照源码核实」的三处MVC 适配器HandlerAdapter、BeanWrapper归装饰器、excludeFilters/includeFilters归策略以及把BeanFactory/FactoryBean归为简单工厂与工厂方法、把后置处理器归为模板方法、把 AOP 调用链归为责任链都属模式归类源码里不会有这种注释⑬ 文中判定链与流程示意是我按转写描述和文档行为重绘的不代表视频画面原图。参考资料 致谢[1] Spring面经-哔哩哔哩77 个分 P 的 Spring 面经合集本文取材其中 P07、P08、P10、P11、P13、P16、P41、P42 八段文中一律称「视频作者」感谢他每题都配了可跑的例子。[2] Apache Tomcat 9.0 配置文档 · The HTTP Connector / Tomcat 10.1 同页线程数、连接数、acceptCount、connectionTimeout默认值。[3] Spring Boot 2.7.18 参考文档 · Application Properties 附录server.tomcat.*属性名与默认值。[4] Spring Framework API · SimpleApplicationEventMulticaster / TransactionalEventListener同步默认、异步 executor 的上下文限制、AFTER_COMMIT与fallbackExecution。[5] Spring Framework v6.1.14 源码 · ThreadPoolTaskExecutor / CorsConfiguration线程池默认值、allowCredentials与*的冲突经 jsDelivr 镜像核对原文。[6] Spring Framework 官网 / Spring Boot 官网 / Nginx 官网 / MySQL 官网 / Apache JMeter 官网 / Apache Kafka 官网 / Apache RocketMQ 官网 / Nacos 官网 / Oracle JDK 17 API。[7] 同系列前八篇Bean 生命周期、循环依赖、容器扩展点、AOP 与代理、事务、Spring MVC、Spring Boot、微服务本篇所有交叉引用只给一句指向不重复展开。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表