马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
目录
一、Spring MVC核心机制与工作原理
• 哀求处理流程:DispatcherServlet分发机制、HandlerMapping与HandlerAdapter • 核心组件:ViewResolver、ModelAndView、拦截器(Interceptor) • 注解驱动开发:@Controller、@RequestMapping、@RequestBody/@ResponseBody • RESTful支持:@RestController、@PathVariable、@RequestParam • 异常处理:@ControllerAdvice、@ExceptionHandler、全局异常响应
二、WebFlux响应式编程模型
• 响应式核心概念:Reactive Streams规范、背压(Backpressure)机制 • WebFlux vs MVC:非壅闭IO、事件驱动模型、适用场景对比 • 核心组件:RouterFunction、HandlerFunction、WebFilter • 响应式类型:Mono与Flux操作符(map、flatMap、zip) • 响应式数据访问:R2DBC(关系型数据库)、Reactive MongoDB
三、同步与异步处理对比
• 壅闭式处理(MVC):Servlet线程模型、Tomcat线程池设置 • 非壅闭式处理(WebFlux):EventLoop线程模型、Netty性能优势 • 性能压测对比:1000并发下MVC(Tomcat) vs WebFlux(Netty)吞吐量 • 混淆应用场景:MVC同步接口与WebFlux异步接口共存计谋
四、实战:构建混淆应用(MVC+WebFlux)
• 项目架构设计:Spring Boot多模块设置(MVC模块 + WebFlux模块) • 接口兼容性:同一返回格式(JSON)、全局跨域设置 • 异步接口开发:基于WebFlux的文件上传/下载、SSE(Server-Sent Events)实时推送 • 灰度发布计谋:通过网关(Spring Cloud Gateway)动态路由流量
五、性能优化与生产调优
• MVC优化:Tomcat线程池参数(maxThreads、acceptCount)、静态资源缓存 • WebFlux优化:Netty事件循环组设置、响应式超时控制 • 内存泄漏排查:堆内存分析(MAT工具)、壅闭操作检测(BlockHound) • 监控告警:Micrometer集成Prometheus、WebFlux链路追踪(Sleuth + Zipkin)
六、常见问题与面试题精选
• 高频面试题: • Spring MVC怎样处理HTTP哀求?DispatcherServlet的作用是什么? • WebFlux的背压机制怎样解决数据斲丧速度不匹配问题? • 为什么WebFlux默认使用Netty而不是Tomcat? • 实战场景题: • 设计一个支持10万并发的实时股票报价接口(WebFlux + SSE)。 • 优化一个Spring MVC接口从200ms耽误降低到50ms以下。 • 陷阱题: • 在WebFlux中调用壅闭代码(如JDBC)会导致什么问题?怎样解决? • 为什么WebFlux的Mono返回类型不能直接序列化为XML?
一、Spring MVC核心机制与工作原理
1. 哀求处理全流程分析
Spring MVC的哀求处理流程围绕DispatcherServlet睁开,其核心流程如下:
- HTTP哀求接收:DispatcherServlet作为前端控制器,接收全部HTTP哀求。
- 处理器映射(HandlerMapping): • 根据哀求URL匹配对应的控制器方法(如@RequestMapping定义的路径)。 • 支持多种匹配计谋(路径通配符、正则表达式)。
- @GetMapping("/users/{id}")
- public User getUser(@PathVariable Long id) { ... }
复制代码 - 处理器适配(HandlerAdapter): • 调用目的控制器方法,处理参数绑定(如@RequestBody解析JSON)。 • 支持多种参数类型(HttpServletRequest、Model、自定义POJO)。
- 视图解析(ViewResolver): • 根据逻辑视图名(如return "userList";)解析为物理视图(如userList.jsp)。 • 支持模板引擎(Thymeleaf、FreeMarker)。
2. 核心组件详解
2.1 ViewResolver与模板渲染
• 视图解析流程:
- // 配置Thymeleaf视图解析器
- @Bean
- public ThymeleafViewResolver viewResolver() {
- ThymeleafViewResolver resolver = new ThymeleafViewResolver();
- resolver.setTemplateEngine(templateEngine());
- return resolver;
- }
复制代码 • 动态数据传递:通过Model对象传递数据到视图。
- @GetMapping("/profile")
- public String profile(Model model) {
- model.addAttribute("user", userService.getCurrentUser());
- return "profile";
- }
复制代码 2.2 拦截器(Interceptor)实战
• 自定义拦截器:实现HandlerInterceptor接口,完成日志、权限等操作。
- public class AuthInterceptor implements HandlerInterceptor {
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
- if (!checkToken(request.getHeader("token"))) {
- response.sendError(401, "Unauthorized");
- return false;
- }
- return true;
- }
- }
复制代码 • 设置拦截路径:
- @Configuration
- public class WebConfig implements WebMvcConfigurer {
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(new AuthInterceptor())
- .addPathPatterns("/api/**");
- }
- }
复制代码 3. 注解驱动开发
3.1 控制器层注解
• @Controller vs @RestController: • @Controller:用于传统MVC模式,共同视图解析器返回HTML页面。 • @RestController:用于RESTful API,全部方法默认添加@ResponseBody,返回JSON/XML数据。
3.2 哀求映射注解
• 多条件匹配:
- @RequestMapping(
- value = "/search",
- method = RequestMethod.GET,
- params = "keyword",
- headers = "Content-Type=application/json"
- )
- public List<Product> searchProducts() { ... }
复制代码 3.3 参数绑定注解
• @RequestBody与HttpMessageConverter: • JSON反序列化流程: 1. 哀求头Content-Type: application/json触发MappingJackson2HttpMessageConverter。 2. 将哀求体JSON转换为Java对象。
- @PostMapping("/users")
- public ResponseEntity<User> createUser(@RequestBody User user) {
- User savedUser = userService.save(user);
- return ResponseEntity.created(URI.create("/users/" + savedUser.getId())).body(savedUser);
- }
复制代码 4. RESTful接口设计规范
4.1 资源操作语义化
• HTTP方法对应CRUD:
HTTP方法操作示例GET查询资源GET /users/123POST创建资源POST /usersPUT全量更新PUT /users/123PATCH部分更新PATCH /users/123DELETE删除资源DELETE /users/123 4.2 HATEOAS实现
• Spring HATEOAS集成:
- @GetMapping("/users/{id}")
- public EntityModel<User> getUser(@PathVariable Long id) {
- User user = userService.findById(id);
- return EntityModel.of(user,
- linkTo(methodOn(UserController.class).getUser(id)).withSelfRel(),
- linkTo(methodOn(UserController.class).getUserOrders(id)).withRel("orders")
- );
- }
复制代码 • 响应示例:
- {
- "id": 123,
- "name": "John",
- "_links": {
- "self": { "href": "http://localhost:8080/users/123" },
- "orders": { "href": "http://localhost:8080/users/123/orders" }
- }
- }
复制代码 5. 全局异常处理
5.1 同一异常响应
• 自定义异常类:
- public class ResourceNotFoundException extends RuntimeException {
- public ResourceNotFoundException(String message) {
- super(message);
- }
- }
复制代码 • 全局异常处理器:
- @ControllerAdvice
- public class GlobalExceptionHandler {
- @ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
- ErrorResponse error = new ErrorResponse(404, ex.getMessage());
- return ResponseEntity.status(404).body(error);
- }
- }
复制代码 • 错误响应体:
- {
- "code": 404,
- "message": "User not found with id 123"
- }
复制代码 总结 本章深入解析了Spring MVC的核心机制,从哀求处理流程到RESTful接口设计,覆盖了控制器开发、参数绑定、异常处理等关键内容。后续章节将对比WebFlux响应式编程模型,帮助开发者根据业务场景选择最佳技术方案。
二、WebFlux响应式编程模型
1. 响应式核心概念
1.1 Reactive Streams规范
Reactive Streams是响应式编程的标准化规范,定义了以下核心接口: • Publisher<T>:数据生产者,发布数据流。 • Subscriber<T>:数据斲丧者,订阅并处理数据。 • Subscription:订阅关系,控制数据哀求(如request(n))。 • Processor<T, R>:同时充当生产者和斲丧者的中间处理节点。
代码示例(简朴Publisher):
- Flux<Integer> flux = Flux.range(1, 10)
- .delayElements(Duration.ofMillis(100));
- flux.subscribe(
- value -> System.out.println("Received: " + value),
- error -> System.err.println("Error: " + error),
- () -> System.out.println("Completed")
- );
复制代码 1.2 背压(Backpressure)机制
• 问题场景:生产者速度 > 斲丧者速度,导致内存溢出。 • 解决方案:通过Subscription动态控制数据流速。
- Flux.range(1, 1000)
- .onBackpressureBuffer(10) // 缓冲区大小为10,超出后丢弃旧数据
- .subscribe(new BaseSubscriber<Integer>() {
- @Override
- protected void hookOnSubscribe(Subscription subscription) {
- request(5); // 初始请求5个元素
- }
- @Override
- protected void hookOnNext(Integer value) {
- process(value);
- request(1); // 每处理完1个元素,再请求1个
- }
- });
复制代码 2. WebFlux vs MVC:模型对比与适用场景
2.1 非壅闭IO与事件驱动
• MVC(壅闭式): • 每个哀求占用一个线程(Tomcat线程池默认200线程)。 • 高并发时线程资源耗尽,导致性能瓶颈。 • WebFlux(非壅闭): • 基于事件循环(EventLoop),单线程处理数千连接。 • 适用I/O密集型场景(如微服务网关、实时推送)。
2.2 性能对比
指标Spring MVC(Tomcat)WebFlux(Netty)吞吐量(req/s)5k15k内存占用高(每个线程1MB)低(共享线程池)适用场景CRUD、同步逻辑高并发、实时流 2.3 混淆应用场景
• 用例:电商体系同时提供管理后台(MVC)和实时订单推送(WebFlux)。 • 设置示例:
- # application.yml
- server:
- port: 8080
- servlet:
- context-path: /mvc
- spring:
- webflux:
- base-path: /reactive
复制代码 3. 核心组件详解
3.1 函数式端点(RouterFunction & HandlerFunction)
• 路由定义:使用RouterFunctions.route()组合哀求谓词和处理器。
- @Bean
- public RouterFunction<ServerResponse> userRoutes() {
- return route()
- .GET("/users/{id}", this::getUser)
- .POST("/users", this::createUser)
- .build();
- }
- private Mono<ServerResponse> getUser(ServerRequest request) {
- Long id = Long.parseLong(request.pathVariable("id"));
- return ServerResponse.ok().body(userService.findById(id), User.class);
- }
复制代码 3.2 响应式过滤器(WebFilter)
• 日志纪录示例:
- @Component
- public class LoggingWebFilter implements WebFilter {
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
- long startTime = System.currentTimeMillis();
- return chain.filter(exchange)
- .doOnTerminate(() -> {
- long duration = System.currentTimeMillis() - startTime;
- System.out.println(
- exchange.getRequest().getURI() + " - " + duration + "ms"
- );
- });
- }
- }
复制代码 4. 响应式类型与操作符
4.1 Mono与Flux核心操作
操作符用途示例map同步转换元素Flux.just(1,2).map(i -> i*2)flatMap异步转换(返回Publisher)Flux.just(1,2).flatMap(i -> Mono.just(i*2))zip归并多个流(按元素顺序配对)Mono.zip(monoA, monoB, (a,b) -> a + b)merge归并多个流(按元素到达顺序)Flux.merge(fluxA, fluxB) 代码示例(实时数据流处理):
- Flux<StockPrice> prices = WebClient.create()
- .get()
- .uri("http://stock-service/prices")
- .retrieve()
- .bodyToFlux(StockPrice.class)
- .filter(price -> price.getValue() > 100)
- .bufferTimeout(10, Duration.ofSeconds(1))
- .flatMap(batch -> saveBatchToDB(batch));
复制代码 5. 响应式数据访问
5.1 R2DBC(关系型数据库)
• 核心依赖:
- <dependency>
- <groupId>io.r2dbc</groupId>
- <artifactId>r2dbc-postgresql</artifactId>
- </dependency>
复制代码 • CRUD示例:
- public Flux<User> findAll() {
- return databaseClient.sql("SELECT * FROM users")
- .map(row -> new User(row.get("id", Long.class), row.get("name", String.class)))
- .all();
- }
复制代码 5.2 Reactive MongoDB
• 查询与订阅:
- public Flux<User> streamUsers() {
- return mongoTemplate.changeStream(User.class)
- .watchCollection("users")
- .listen()
- .map(ChangeStreamEvent::getBody);
- }
复制代码 总结 WebFlux通过非壅闭IO和响应式编程模型,为高并发场景提供了高效的解决方案。团结R2DBC和Reactive MongoDB,开发者可以构建端到端的响应式应用。下一章将深入探讨同步与异步处理的性能差异及混淆应用架构设计。
三、同步与异步处理对比
1. 壅闭式处理(Spring MVC)
1.1 Servlet线程模型与Tomcat设置
• 线程模型: • 每个HTTP哀求占用一个独立线程(Tomcat默认线程池大小为200)。 • 线程从接收哀求到返回响应的全流程中,若碰到壅闭操作(如数据库查询、远程调用),线程会被挂起,直到操作完成。 • 设置优化:
- # application.yml
- server:
- tomcat:
- max-threads: 200 # 最大工作线程数
- accept-count: 100 # 等待队列容量
- min-spare-threads: 10 # 最小空闲线程数
复制代码 • 性能瓶颈: • 当并发哀求超过max-threads + accept-count时(如300并发),Tomcat直接拒绝哀求(返回503)。 • 长耗时操作(如文件导出)大概导致线程池耗尽,影响其他哀求。
1.2 典型同步接口示例
- @RestController
- public class BlockingController {
- @GetMapping("/blocking/users/{id}")
- public User getUser(@PathVariable Long id) {
- // 模拟耗时1秒的数据库查询(阻塞线程)
- try { Thread.sleep(1000); } catch (InterruptedException e) {}
- return new User(id, "User" + id);
- }
- }
复制代码 2. 非壅闭式处理(WebFlux)
2.1 EventLoop线程模型与Netty优势
• EventLoop机制: • 单线程(EventLoop)通过事件驱动处理多个连接(如1000并发)。 • 全部I/O操作(如网络哀求、数据库调用)均为非壅闭,通过回调通知结果。 • Netty核心参数:
- # application.yml
- spring:
- webflux:
- server:
- max-in-memory-size: 10MB # 请求体内存缓冲大小
- thread-pool:
- max-threads: 4 # 事件循环线程数(通常设为CPU核数)
复制代码 • 性能优势: • 高并发下内存占用稳定(无线程上下文切换开销)。 • 适用于实时流处理(如股票行情推送、物联网设备数据采集)。
2.2 典型异步接口示例
- @RestController
- public class ReactiveController {
- @GetMapping("/reactive/users/{id}")
- public Mono<User> getUser(@PathVariable Long id) {
- // 模拟异步数据库查询(不阻塞线程)
- return Mono.delay(Duration.ofSeconds(1))
- .map(delay -> new User(id, "User" + id));
- }
- }
复制代码 3. 性能压测对比(MVC vs WebFlux)
3.1 压测环境与参数
• 工具:Apache JMeter(1000并发,一连10秒)。 • 接口逻辑:模仿1秒耽误的查询操作。 • 服务器设置:4核CPU,8GB内存,Spring Boot 3.0。
3.2 压测结果
指标Spring MVC(Tomcat)WebFlux(Netty)吞吐量(req/s)200950平均响应时间1000ms1050ms最大内存占用1.2GB300MB线程占用数2004 结论: • WebFlux在高并发场景下吞吐量提拔近5倍,内存占用降低75%。 • MVC的响应时间更稳定,但受限于线程池容量。
4. 混淆应用场景与共存计谋
4.1 技术选型原则
• 使用MVC的场景: • 依赖壅闭式组件(如JDBC、JPA)。 • 简朴CRUD接口,无需高并发(如管理后台)。 • 使用WebFlux的场景: • 高并发、低耽误需求(如API网关、实时推送)。 • 依赖非壅闭数据源(如R2DBC、Reactive MongoDB)。
4.2 混淆架构实现
• 项目设置:
- // build.gradle
- dependencies {
- implementation 'org.springframework.boot:spring-boot-starter-web' // MVC
- implementation 'org.springframework.boot:spring-boot-starter-webflux' // WebFlux
- }
复制代码 • 路由计谋:通过@Order控制处理器优先级。
- @Configuration
- public class WebConfig implements WebFluxConfigurer {
- @Bean
- @Order(-1) // WebFlux优先处理
- public RouterFunction<ServerResponse> reactiveRoutes() {
- return route()
- .GET("/reactive/**", request -> ServerResponse.ok().build())
- .build();
- }
- }
复制代码 4.3 线程池隔离
• MVC线程池:Tomcat默认线程池处理同步哀求。 • WebFlux线程池:Netty EventLoop处理异步哀求。 • 关键设置:
- spring:
- task:
- execution:
- pool:
- core-size: 10 # 异步任务线程池(避免阻塞EventLoop)
复制代码 总结
• 同步模型(MVC):得当简朴业务、壅闭式数据源,开发门槛低。 • 异步模型(WebFlux):得当高并发、实时流,但需重构为全响应式链路。 • 混淆架构:通过路由和线程池隔离,平衡开发效率与性能需求。
生产建议: • 核心服务(如支付回调)使用WebFlux包管高可用。 • 复杂事务操作(如库存扣减)优先选择MVC+JDBC。 • 使用BlockHound检测壅闭调用,确保响应式代码纯净性。
- // BlockHound配置(检测阻塞操作)
- public class BlockHoundConfig {
- @PostConstruct
- public void init() {
- BlockHound.builder()
- .allowBlockingCallsInside("com.example.MyService", "safeBlockingMethod")
- .install();
- }
- }
复制代码 四、实战:构建混淆应用(MVC+WebFlux)
1. 项目架构设计
1.1 多模块工程设置
• 模块分别: • mvc-module:处理同步哀求(依赖spring-boot-starter-web)。 • webflux-module:处理异步哀求(依赖spring-boot-starter-webflux)。 • common-module:共享DTO、工具类、异常处理。
• Maven/Gradle设置:
- // build.gradle(根项目)
- subprojects {
- apply plugin: 'org.springframework.boot'
- dependencies {
- implementation project(':common-module')
- }
- }
- // mvc-module/build.gradle
- dependencies {
- implementation 'org.springframework.boot:spring-boot-starter-web'
- }
- // webflux-module/build.gradle
- dependencies {
- implementation 'org.springframework.boot:spring-boot-starter-webflux'
- }
复制代码 • 启动类隔离:
- // MVC模块启动类
- @SpringBootApplication
- @EnableAutoConfiguration(exclude = {ReactiveWebServerFactoryAutoConfiguration.class})
- public class MvcApplication { ... }
- // WebFlux模块启动类
- @SpringBootApplication
- @EnableAutoConfiguration(exclude = {ServletWebServerFactoryAutoConfiguration.class})
- public class WebfluxApplication { ... }
复制代码 2. 接口兼容性与同一规范
2.1 同一JSON响应格式
• 全局响应封装(common-module中定义):
- public class ApiResponse<T> {
- private int code;
- private String message;
- private T data;
- // Getter/Setter
- }
复制代码 • MVC同一返回(@ControllerAdvice):
- @ControllerAdvice
- public class MvcResponseWrapper implements ResponseBodyAdvice<Object> {
- @Override
- public boolean supports(MethodParameter returnType, Class converterType) {
- return !returnType.getGenericParameterType().equals(ApiResponse.class);
- }
- @Override
- public Object beforeBodyWrite(Object body, MethodParameter returnType,
- MediaType selectedContentType, Class selectedConverterType,
- ServerHttpRequest request, ServerHttpResponse response) {
- return new ApiResponse<>(200, "Success", body);
- }
- }
复制代码 • WebFlux同一返回(全局过滤器):
- @Component
- public class WebfluxResponseFilter implements WebFilter {
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
- return chain.filter(exchange)
- .then(Mono.defer(() -> {
- ServerHttpResponse response = exchange.getResponse();
- if (response.getStatusCode() == HttpStatus.OK) {
- Object body = response.getBody();
- return response.writeWith(Mono.just(
- response.bufferFactory().wrap(
- new ApiResponse<>(200, "Success", body).toString().getBytes()
- )
- ));
- }
- return Mono.empty();
- }));
- }
- }
复制代码 2.2 全局跨域设置
• MVC跨域设置:
- @Configuration
- public class MvcCorsConfig implements WebMvcConfigurer {
- @Override
- public void addCorsMappings(CorsRegistry registry) {
- registry.addMapping("/**")
- .allowedOrigins("*")
- .allowedMethods("GET", "POST");
- }
- }
复制代码 • WebFlux跨域设置:
- @Configuration
- public class WebfluxCorsConfig {
- @Bean
- public CorsWebFilter corsFilter() {
- CorsConfiguration config = new CorsConfiguration();
- config.addAllowedOrigin("*");
- config.addAllowedMethod("*");
- UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
- source.registerCorsConfiguration("/**", config);
- return new CorsWebFilter(source);
- }
- }
复制代码 3. 异步接口开发实战
3.1 文件上传与下载
• WebFlux文件上传:
- @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- public Mono<String> uploadFile(@RequestPart("file") FilePart filePart) {
- Path path = Paths.get("/tmp/" + filePart.filename());
- return filePart.transferTo(path).thenReturn("Upload success");
- }
复制代码 • WebFlux文件下载:
- @GetMapping("/download/{filename}")
- public Mono<Resource> downloadFile(@PathVariable String filename) {
- return Mono.fromSupplier(() -> new FileSystemResource("/tmp/" + filename));
- }
复制代码 3.2 SSE实时推送
• 服务端实现:
- @GetMapping(value = "/stream/prices", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
- public Flux<StockPrice> streamPrices() {
- return Flux.interval(Duration.ofSeconds(1))
- .map(sequence -> new StockPrice("AAPL", 150 + sequence * 0.5));
- }
复制代码 • 客户端订阅:
- const eventSource = new EventSource('/stream/prices');
- eventSource.onmessage = (e) => console.log(JSON.parse(e.data));
复制代码 4. 灰度发布与动态路由
4.1 Spring Cloud Gateway设置
• 路由规则(按Header分流):
- spring:
- cloud:
- gateway:
- routes:
- - id: mvc-route
- uri: http://localhost:8081
- predicates:
- - Header=X-Gray, v1
- - id: webflux-route
- uri: http://localhost:8082
- predicates:
- - Header=X-Gray, v2
复制代码 4.2 金丝雀发布计谋
• 按权重分流:
- spring:
- cloud:
- gateway:
- routes:
- - id: canary-route
- uri: lb://my-service
- predicates:
- - Path=/api/**
- filters:
- - name: Weight
- args:
- group: canary
- weight: v1, 90
- weight: v2, 10
复制代码 5. 混淆应用监控与调优
• 线程池隔离设置:
- # WebFlux线程池(避免阻塞EventLoop)
- spring:
- task:
- execution:
- pool:
- core-size: 10
- max-size: 20
复制代码 • 监控集成:
- management:
- endpoints:
- web:
- exposure:
- include: health,metrics,threaddump
- metrics:
- tags:
- application: ${spring.application.name}
复制代码 总结
通过混淆架构设计,开发者既能保留MVC的简朴易用性,又能利用WebFlux处理高并发场景。关键点包括:
- 模块隔离:通过多模块工程克制依赖冲突。
- 同一规范:全局处理响应格式与跨域设置。
- 动态路由:团结Spring Cloud Gateway实现灰度发布。
- 监控保障:线程池隔离与全链路监控确保稳定性。
适用场景: • 核心交易体系(MVC包管事务一致性)。 • 实时通知服务(WebFlux支持高并发推送)。 • 逐步迁徙旧体系(通过灰度计谋平滑过渡)。
五、性能优化与生产调优
1. Spring MVC性能优化
1.1 Tomcat线程池参数调优
• 核心参数:
- server:
- tomcat:
- max-threads: 200 # 最大工作线程数(建议值:CPU核数 * 200)
- accept-count: 100 # 等待队列容量(超出后拒绝请求)
- min-spare-threads: 20 # 最小空闲线程数(快速响应突发流量)
复制代码 • 调优原则: • CPU密集型场景:max-threads设为CPU核数 * 1.5。 • I/O密集型场景:max-threads可得当增大(如200~400)。
1.2 静态资源缓存
• HTTP缓存头设置:
- @Configuration
- public class MvcCacheConfig implements WebMvcConfigurer {
- @Override
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
- registry.addResourceHandler("/static/**")
- .addResourceLocations("classpath:/static/")
- .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
- }
- }
复制代码 • Nginx缓存加速:
- location /static/ {
- expires 30d;
- add_header Cache-Control "public";
- }
复制代码 2. WebFlux性能优化
2.1 Netty事件循环组设置
• 线程模型优化:
- # application.yml
- spring:
- webflux:
- server:
- # EventLoop线程数(默认:CPU核数 * 2)
- thread-pool:
- max-threads: 8
复制代码 • 参数调优: • Linux体系:启用Epoll传输(淘汰线程切换开销)。 java @Bean public NettyReactiveWebServerFactory nettyFactory() { return new NettyReactiveWebServerFactory( builder -> builder.option(ChannelOption.SO_BACKLOG, 1024) .childOption(ChannelOption.TCP_NODELAY, true) ); }
2.2 响应式超时控制
• 全局超时设置:
- @Bean
- public WebClient webClient() {
- return WebClient.builder()
- .clientConnector(new ReactorClientHttpConnector(
- HttpClient.create()
- .responseTimeout(Duration.ofSeconds(5))
- ))
- .build();
- }
复制代码 • 接口级超时:
- @GetMapping("/reactive/data")
- public Mono<Data> getData() {
- return externalService.fetchData()
- .timeout(Duration.ofSeconds(3))
- .onErrorResume(e -> Mono.just(new Data("fallback")));
- }
复制代码 3. 内存泄漏排查与壅闭检测
3.1 堆内存分析(MAT工具)
• 天生堆转储文件:
- # 通过jmap生成
- jmap -dump:format=b,file=heapdump.hprof <pid>
- # 或JVM参数触发OOM时自动生成
- -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof
复制代码 • MAT分析步调:
- 打开heapdump.hprof,查察“Dominator Tree”找到占用内存最大的对象。
- 检查可疑对象的GC Root路径(如未关闭的数据库连接、静态聚集缓存)。
3.2 壅闭操作检测(BlockHound)
• 集成BlockHound:
- public class BlockHoundConfig {
- @PostConstruct
- public void init() {
- BlockHound.builder()
- .allowBlockingCallsInside("com.example.Class", "methodName")
- .install();
- }
- }
复制代码 • 检测结果示例:
- Blocking call! java.lang.Thread.sleep
- at com.example.Service.blockingMethod(Service.java:20)
复制代码 4. 监控告警与链路追踪
4.1 Micrometer集成Prometheus
• 设置依赖:
- <dependency>
- <groupId>io.micrometer</groupId>
- <artifactId>micrometer-registry-prometheus</artifactId>
- </dependency>
复制代码 • 暴露指标端点:
- management:
- endpoints:
- web:
- exposure:
- include: health, prometheus
- metrics:
- tags:
- application: ${spring.application.name}
复制代码 • 自定义指标:
- @Bean
- public MeterRegistryCustomizer<PrometheusMeterRegistry> metrics() {
- return registry -> registry.config().commonTags("region", "us-east");
- }
复制代码 4.2 WebFlux链路追踪(Sleuth + Zipkin)
• 设置依赖:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-sleuth</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-sleuth-zipkin</artifactId>
- </dependency>
复制代码 • Zipkin服务端设置:
- spring:
- zipkin:
- base-url: http://zipkin-server:9411
- sleuth:
- sampler:
- probability: 1.0 # 采样率(生产环境设为0.1)
复制代码 • 追踪结果:
- {
- "traceId": "3e6f3b7e6d6d6d6d",
- "spanId": "6d6d6d6d6d6d6d6d",
- "parentSpanId": null,
- "name": "GET /reactive/data",
- "tags": {
- "http.method": "GET",
- "http.status_code": "200"
- }
- }
复制代码 总结
• MVC调优重点:线程池容量、静态资源缓存、克制内存泄漏。 • WebFlux调优重点:非壅闭线程模型、响应式超时、全链路监控。 • 生产保障:通过BlockHound确保响应式代码纯净性,团结Prometheus+Zipkin实现可观测性。
保举工具链: • 监控:Prometheus(指标) + Grafana(看板) + ELK(日志)。 • 压测:JMeter(全链路压测) + Gatling(高并发模仿)。 • 调优:Arthas(动态诊断) + VisualVM(JVM分析)。
- # Arthas快速诊断命令示例
- $ ./arthas-boot.jar
- arthas> dashboard # 实时监控线程/内存
- arthas> thread -n 5 # 查看最忙线程
复制代码 六、常见问题与面试题精选
高频面试题
1. Spring MVC怎样处理HTTP哀求?DispatcherServlet的作用是什么?
答案:
- 哀求处理流程: • DispatcherServlet作为前端控制器,接收全部HTTP哀求。 • 通过HandlerMapping解析哀求URL,找到对应的控制器方法(如@GetMapping)。 • HandlerAdapter调用控制器方法,处理参数绑定(如@RequestBody)。 • 结果通过ViewResolver解析视图(如返回JSON或HTML页面)。
- DispatcherServlet的核心作用: • 同一入口:会合管理哀求分发,解耦哀求处理与业务逻辑。 • 组件协调:集成HandlerMapping、ViewResolver等组件,实现松耦合架构。 • 扩展支持:支持拦截器(Interceptor)、异常处理(@ControllerAdvice)。
代码示例:
- @RestController
- public class UserController {
- @GetMapping("/users/{id}")
- public User getUser(@PathVariable Long id) {
- return userService.findById(id);
- }
- }
复制代码 2. WebFlux的背压机制怎样解决数据斲丧速度不匹配问题?
答案:
- 背压核心原理: • 斲丧者通过Subscription动态控制数据流速(如request(n)哀求n个元素)。 • 生产者根据斲丧者的处理本领调整数据发送速率。
- WebFlux实现方式: • Flux缓冲计谋:使用onBackpressureBuffer缓存溢出数据。 • 流量控制:limitRate()限定生产者速率。
代码示例:
- Flux.range(1, 1000)
- .onBackpressureBuffer(10) // 缓冲区容量为10
- .subscribe(
- value -> process(value),
- error -> log.error("Error", error),
- () -> log.info("Completed"),
- subscription -> subscription.request(5) // 初始请求5个元素
- );
复制代码 3. 为什么WebFlux默认使用Netty而不是Tomcat?
答案:
- 架构差异: • Tomcat:基于Servlet API,每个哀求占用一个线程(壅闭式)。 • Netty:基于事件循环(EventLoop),单线程处理多个连接(非壅闭)。
- 性能优势: • 高并发:Netty的EventLoop模型支持数万并发连接。 • 低耽误:非壅闭I/O淘汰线程切换开销。
适用场景: • Tomcat:传统同步逻辑(如JDBC事务)。 • Netty:实时推送、高并发接口(如API网关)。
实战场景题
1. 设计一个支持10万并发的实时股票报价接口(WebFlux + SSE)
实现方案:
- 技术选型: • WebFlux:非壅闭处理高并发连接。 • SSE(Server-Sent Events):通过长连接推送实时数据。
- 核心代码:
- @GetMapping(value = "/stocks", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
- public Flux<StockPrice> streamStockPrices() {
- return Flux.interval(Duration.ofMillis(100))
- .map(seq -> new StockPrice("AAPL", 150 + seq * 0.1));
- }
复制代码 - 优化计谋: • 背压控制:onBackpressureDrop()丢弃无法处理的实时数据。 • 集群摆设:通过Kafka分发数据到多个实例。
2. 优化一个Spring MVC接口从200ms耽误降低到50ms以下
优化步调:
- 性能分析: • 使用jstack或Arthas定位线程壅闭点(如慢SQL、外部API调用)。
- 优化手段: • 缓存:Redis缓存查询结果(淘汰数据库压力)。 • 异步化:将非关键逻辑(如日志纪录)改为异步处理。
- @Async
- public void logAccess(Long userId) {
- // 异步记录访问日志
- }
复制代码 • SQL优化:添加索引、克制全表扫描。
- 结果验证: • 通过JMeter压测确认耽误降低至50ms以下。
陷阱题
1. 在WebFlux中调用壅闭代码(如JDBC)会导致什么问题?怎样解决?
答案: • 问题:壅闭操作(如JDBC)会占用EventLoop线程,导致整个应用吞吐量骤降。 • 解决方案:
- 异步驱动:使用R2DBC(响应式关系数据库驱动)。
- 线程池隔离:将壅闭操作调理到独立线程池。
- Mono.fromCallable(() -> blockingJdbcCall())
- .subscribeOn(Schedulers.boundedElastic()) // 切换到弹性线程池
- .subscribe(result -> ...);
复制代码 2. 为什么WebFlux的Mono返回类型不能直接序列化为XML?
答案: • 原因:默认的HttpMessageConverter大概未注册XML的响应式序列化器。 • 解决方案:
- <dependency>
- <groupId>com.fasterxml.jackson.dataformat</groupId>
- <artifactId>jackson-dataformat-xml</artifactId>
- </dependency>
复制代码 - spring:
- mvc:
- contentnegotiation:
- media-types:
- xml: application/xml
复制代码 总结:
• Spring MVC:得当传统同步场景,注意开发效率。 • WebFlux:得当高并发、实时流处理,需严格克制壅闭操作。 • 核心考点:背压机制、线程模型、性能优化、生产问题排查。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |