7 种提升 Spring Boot 吞吐量神技!

探究 Spring Boot 可以同时处理多少请求 一般来说,CPU 的处理速度、内存的大小、磁盘的读写速度等都会影响到应用程序的并发处理能力。(Spring Boot实现数量与异步请求处理有直接关联) Spring Boot 提供了可扩展的异步请求处理机制,通过使用 CompletableFuture 或 DeferredResult 等异步编程模型来处理请求,可以避免线程阻塞,从而提高并发处理能力。总结一下吧,Spring Boot 同时处理请求的数量受到硬件资源、Web 服务器的选择、配置参数的设置和异步请求处理等多个因素的影响。 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:xhcom.blog.youkuaiyun.com/

article/details/88046026

67c1f1c5462e809a8d9a20ff7b3fd2ac.jpeg


一、异步执行

实现方式二种:

  1. 使用异步注解@aysnc、启动类:添加@EnableAsync注解

  2. JDK 8本身有一个非常好用的Future类——CompletableFuture

@AllArgsConstructor
public class AskThread implements Runnable{
    private CompletableFuture<Integer> re = null;

    public void run() {
        int myRe = 0;
        try {
            myRe = re.get() * re.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(myRe);
    }

    public static void main(String[] args) throws InterruptedException {
        final CompletableFuture<Integer> future = new CompletableFuture<>();
        new Thread(new AskThread(future)).start();
        //模拟长时间的计算过程
        Thread.sleep(1000);
        //告知完成结果
        future.complete(60);
    }
}

在该示例中,启动一个线程,此时AskThread对象还没有拿到它需要的数据,执行到 myRe = re.get() * re.get()会阻塞。我们用休眠1秒来模拟一个长时间的计算过程,并将计算结果告诉future执行结果,AskThread线程将会继续执行。

public class Calc {
    public static Integer calc(Integer para) {
        try {
            //模拟一个长时间的执行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return para * para;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        final CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> calc(50))
                .thenApply((i) -> Integer.toString(i))
                .thenApply((str) -> "\"" + str + "\"")
                .thenAccept(System.out::println);
        future.get();
    }
}

CompletableFuture.supplyAsync方法构造一个CompletableFuture实例,在supplyAsync()方法中,它会在一个新线程中,执行传入的参数。在这里它会执行calc()方法,这个方法可能是比较慢的,但这并不影响CompletableFuture实例的构造速度,supplyAsync()会立即返回。

而返回的CompletableFuture实例就可以作为这次调用的契约,在将来任何场合,用于获得最终的计算结果。

supplyAsync用于提供返回值的情况,CompletableFuture还有一个不需要返回值的异步调用方法runAsync(Runnable runnable),一般我们在优化Controller时,使用这个方法比较多。这两个方法如果在不指定线程池的情况下,都是在ForkJoinPool.common线程池中执行,而这个线程池中的所有线程都是Daemon(守护)线程,所以,当主线程结束时,这些线程无论执行完毕都会退出系统。

核心代码:

CompletableFuture.runAsync(() ->
   this.afterBetProcessor(betRequest,betDetailResult,appUser,id)
);

异步调用使用Callable来实现

@RestController  
public class HelloController {
  
    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
      
    @Autowired  
    private HelloService hello;
  
    @GetMapping("/helloworld")
    public String helloWorldController() {
        return hello.sayHello();
    }
  
    /**
     * 异步调用restful
     * 当controller返回值是Callable的时候,springmvc就会启动一个线程将Callable交给TaskExecutor去处理
     * 然后DispatcherServlet还有所有的spring拦截器都退出主线程,然后把response保持打开的状态
     * 当Callable执行结束之后,springmvc就会重新启动分配一个request请求,然后DispatcherServlet就重新
     * 调用和处理Callable异步执行的返回结果, 然后返回视图
     *
     * @return
     */  
    @GetMapping("/hello")
    public Callable<String> helloController() {
        logger.info(Thread.currentThread().getName() + " 进入helloController方法");
        Callable<String> callable = new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " 进入call方法");
                String say = hello.sayHello();
                logger.info(Thread.currentThread().getName() + " 从helloService方法返回");
                return say;
            }
        };
        logger.info(Thread.currentThread().getName() + " 从helloController方法返回");
        return callable;
    }
}

异步调用的方式 WebAsyncTask

@RestController  
public class HelloController {
  
    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
      
    @Autowired  
    private HelloService hello;
  
        /**
     * 带超时时间的异步请求 通过WebAsyncTask自定义客户端超时间
     *
     * @return
     */  
    @GetMapping("/world")
    public WebAsyncTask<String> worldController() {
        logger.info(Thread.currentThread().getName() + " 进入helloController方法");
  
        // 3s钟没返回,则认为超时
        WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(3000, new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " 进入call方法");
                String say = hello.sayHello();
                logger.info(Thread.currentThread().getName() + " 从helloService方法返回");
                return say;
            }
        });
        logger.info(Thread.currentThread().getName() + " 从helloController方法返回");
  
        webAsyncTask.onCompletion(new Runnable() {
  
            @Override  
            public void run() {
                logger.info(Thread.currentThread().getName() + " 执行完毕");
            }
        });
  
        webAsyncTask.onTimeout(new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " onTimeout");
                // 超时的时候,直接抛异常,让外层统一处理超时异常
                throw new TimeoutException("调用超时");
            }
        });
        return webAsyncTask;
    }
  
    /**
     * 异步调用,异常处理,详细的处理流程见MyExceptionHandler类
     *
     * @return
     */  
    @GetMapping("/exception")
    public WebAsyncTask<String> exceptionController() {
        logger.info(Thread.currentThread().getName() + " 进入helloController方法");
        Callable<String> callable = new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " 进入call方法");
                throw new TimeoutException("调用超时!");
            }
        };
        logger.info(Thread.currentThread().getName() + " 从helloController方法返回");
        return new WebAsyncTask<>(20000, callable);
    }
  
}

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

二、增加内嵌Tomcat的最大连接数

@Configuration
public class TomcatConfig {
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();
        tomcatFactory.addConnectorCustomizers(new MyTomcatConnectorCustomizer());
        tomcatFactory.setPort(8005);
        tomcatFactory.setContextPath("/api-g");
        return tomcatFactory;
    }
    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            //设置最大连接数
            protocol.setMaxConnections(20000);
            //设置最大线程数
            protocol.setMaxThreads(2000);
            protocol.setConnectionTimeout(30000);
        }
    }

}

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

三、使用@ComponentScan()定位扫包比@SpringBootApplication扫包更快

四、默认tomcat容器改为Undertow(Jboss下的服务器,Tomcat吞吐量5000,Undertow吞吐量8000)

<exclusions>
  <exclusion>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-tomcat</artifactId>
  </exclusion>
</exclusions>

改为:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

五、使用 BufferedWriter 进行缓冲

六、Deferred方式实现异步调用

@RestController
public class AsyncDeferredController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final LongTimeTask taskService;
    
    @Autowired
    public AsyncDeferredController(LongTimeTask taskService) {
        this.taskService = taskService;
    }
    
    @GetMapping("/deferred")
    public DeferredResult<String> executeSlowTask() {
        logger.info(Thread.currentThread().getName() + "进入executeSlowTask方法");
        DeferredResult<String> deferredResult = new DeferredResult<>();
        // 调用长时间执行任务
        taskService.execute(deferredResult);
        // 当长时间任务中使用deferred.setResult("world");这个方法时,会从长时间任务中返回,继续controller里面的流程
        logger.info(Thread.currentThread().getName() + "从executeSlowTask方法返回");
        // 超时的回调方法
        deferredResult.onTimeout(new Runnable(){
  
   @Override
   public void run() {
    logger.info(Thread.currentThread().getName() + " onTimeout");
    // 返回超时信息
    deferredResult.setErrorResult("time out!");
   }
  });
        
        // 处理完成的回调方法,无论是超时还是处理成功,都会进入这个回调方法
        deferredResult.onCompletion(new Runnable(){
  
   @Override
   public void run() {
    logger.info(Thread.currentThread().getName() + " onCompletion");
   }
  });
        
        return deferredResult;
    }
}

七、异步调用可以使用AsyncHandlerInterceptor进行拦截

@Component
public class MyAsyncHandlerInterceptor implements AsyncHandlerInterceptor {
 
 private static final Logger logger = LoggerFactory.getLogger(MyAsyncHandlerInterceptor.class);
 
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {
  return true;
 }
 
 @Override
 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
   ModelAndView modelAndView) throws Exception {
// HandlerMethod handlerMethod = (HandlerMethod) handler;
  logger.info(Thread.currentThread().getName()+ "服务调用完成,返回结果给客户端");
 }
 
 @Override
 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
   throws Exception {
  if(null != ex){
   System.out.println("发生异常:"+ex.getMessage());
  }
 }
 
 @Override
 public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {
  
  // 拦截之后,重新写回数据,将原来的hello world换成如下字符串
  String resp = "my name is chhliu!";
  response.setContentLength(resp.length());
  response.getOutputStream().write(resp.getBytes());
  
  logger.info(Thread.currentThread().getName() + " 进入afterConcurrentHandlingStarted方法");
 }
 
}


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

7dc7754fa6495bd978120cb4af2a99fd.png

已在知识星球更新源码解析如下:

e3966cd7dc08b45f40e79f447f1c286f.jpeg

b48a5d7d4f4c3ce49d126d95239eac24.jpeg

5ef37970c9f46626b4e3495ee484a5af.jpeg

d5bdc1aa3bbb5b66192f56281643d65e.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
springboot-:记录实现高并发的解决方案 springboot-demo 记录实现高并发的解决方案 day01 1.springboot整合druid多数据源和log4j2 (1)实现数据源,主数据库(写),从数据库(读),读写分离的方案之一 (2)mysql主从复制,保持数据一致性 (3)使用druid的监控功能 (4)log4j2日志介绍和配置说明 2.redis哨兵模式的实现,实现高可用 主库写,从库读 day02 (1)两次md5,第一次客户端明文+固定盐值 第二次客户端第一次前端传过来的+随机盐值 项目里面模拟的是登录查询的过程 整个过程分析如下:首先,第一次用户注册的时候输入框输入明文,然后前端再加固定盐值, 第二次前端传过来第一次加密的+后端随机生成的盐值,该盐值要存入数据库 查询的时候,第一次客户端明文+固定盐值,传入后端,第二次后端去查询数据库注册时候后端随机生成的盐值, 把第一次前端传过来的加密的+数据库查询的 立即下载

相关推荐

分布式 Agent 系统设计:高并发场景下的挑战与解决方案

分布式 Agent 系统由多个分布在不同节点上的智能 Agent 组成,这些 Agent 具有自主决策能力,能够通过通信协作完成复杂任务。每个 Agent 可以看作是一个独立的实体,具备感知环境、处理信息、执行动作的功能,它们相互协作,共同实现系统的整体目标。分布式 Agent 系统在高并发场景下面临着资源调度、通信延迟、状态一致性、容错处理和性能瓶颈等诸多挑战。通过采用动态资源分配、高效通信协议、分布式共识算法、冗余备份等解决方案,可以有效应对这些挑战,提高系统的性能、可靠性和可用性。

shuizhudan223的博客 1294

Spring Boot 接口支持高并发

在计算机领域,高并发指的是系统在同一时间内处理大量的请求。在Web应用程序中,高并发通常是指同时有很多用户访问同一个接口,这时系统需要能够快速响应并处理这些请求。如果系统无法处理这些请求,就会导致性能下降、响应时间变长、甚至崩溃。本文介绍了Spring Boot如何支持高并发的接口,并提供了具体的实现方案和示例代码。在实际开发中,我们可以使用线程池和异步处理来提高系统的并发处理能力。通过合理地使用这些工具和功能,我们可以构建出高质量、高性能的应用程序。

果酱 の 博客 8896

USB接口ESD防护设计实战:从金属外壳到信号线的完整避坑指南

本文深入探讨USB接口ESD防护设计的实战要点,聚焦金属外壳作为ESD能量泄放关键通道的处理策略。文章详细解析了从外壳接地路径控制、信号线TVS管选型与布局,到PCB分区及电源线滤波等完整设计流程,旨在帮助硬件工程师构建系统级防护,避免常见设计误区,确保产品通过严苛的静电测试。

k8l9m0n的博客 482

Spring Boot中的高并发处理

高并发是指系统能够处理大量并发请求的能力。在互联网应用中,高并发处理是一个重要的性能指标,涉及到系统的吞吐量、响应时间和资源利用率等。为了实现高并发处理,我们需要从多个方面进行优化,包括硬件层面、网络层面、操作系统层面和应用层面。在Spring Boot中实现高并发处理需要综合考虑异步处理、线程池、缓存、数据库连接池和限流等多种技术。通过合理的配置和优化,可以显著提高系统的并发处理能力,提升用户体验和系统的稳定性。

技术研究中心 3679

【Lammps】MS将cif通过msi2lmp.exe转为data文件

在Materials Studio中打开cif文件,在Modules工具行选择Forcite>calculation>Energy中选用cvff力场,点击more,不要运行run,在more中取消勾选calculate automatically,点击calculate,然后叉掉后在file>export导出car文件,同步生成了mdf文件。对于MS中没有的立场,选择之后点calculate会报错,右键选择label,然后根据Forcite选择原子,会发现有力场的有标号,没有力场的MS没有对选择标号。

zhangguoliang624的博客 3674

【锂离子电池力学耦合及相场法模拟技术与应用】

8. 电化学仿真软件的使用与案例分析 (1) 各向异性纳米线锂化应力分析(实例讲解1) (2) 化学反应及死锂现象研究(案例分析2)(3) 锂化循环损伤计算(案例分析3)6. 4. 电池材料的力学与电化学耦合性能分析(1) 耦合效应对电池性能的影响(2) 耦合模型的验证与应。5. 5. 电池颗粒、极片、电芯尺度力-电-化-热多场耦合模型概述力学-7. 颗粒尺度耦合模型在电池失效分析中的应用。2. 2. 电池电极材料的分类与特性。5. (2) 耦合模型的验证与应用。电化学耦合模型与仿真。

weixin_51101456的博客 524

Spring Boot接口实现百万并发

随着互联网的发展,越来越多的应用需要支持高并发。在这种情况下,如何实现高并发成为了一个重要的问题。Spring Boot是一个非常流行的Java框架,它提供了很多方便的功能来支持高并发。本文将介绍如何使用Spring Boot来实现百万并发。Spring Boot是一个基于Spring框架的快速开发框架,它可以帮助开发人员快速构建Spring应用程序。Spring Boot提供了很多默认的配置,可以减少开发人员的工作量。同时,Spring Boot也提供了很多扩展功能,可以帮助开发人员更好地处理业务逻辑。

果酱 の 博客 1万+

使用RV1126实现人脸识别——将Facenet模型转换为RKNN模型

在本文中,我们将探讨如何在RV1126芯片上实现人脸识别,并将Facenet模型转换为RKNN(Rockchip Neural Network)模型,以在RV1126上进行高效的人脸识别。Fine-tuning是指在预训练模型的基础上,使用自己的数据集进行进一步训练,以适应特定的任务。同时,我们需要下载Facenet模型的预训练权重,这些权重将作为我们的基础模型。综上所述,我们详细介绍了如何在RV1126上实现人脸识别,并将Facenet模型转换为RKNN模型。方法将模型导出为RKNN格式的文件。

code_program481的博客 1524

7个提升 Spring Boot 吞吐量的神技,让你的代码飞起来!

日常开发中,有很多的代码优化,其实在编码的过程中就能顺手完成;为了避免日后还得再专门花时间来做优化,下面就列举几种简单且好用的优化小技巧,轻松提升接口的吞吐量;一、异步执行实现方式二种:使用异步注解 @aysnc、启动类:添加 @EnableAsync 注解JDK 8 本身有一个非常好用的 Future 类——CompletableFuture@AllArgsConstructor public...

372

3.摄像头组件- CVP (ISP)

本文介绍 车载摄像头组件-ISP

2401_83458819的博客 1618

【华为OD机试真题 2025C卷】238、贪吃蛇 | 机试真题+思路参考+代码解析(C++、Java、Py、C语言、JS)

【华为OD机试真题 2025C卷】238、贪吃蛇 | 机试真题+思路参考+代码解析(C++、Java、Py、C语言、JS) 华为od机试,华为od机试真题,华为od机试E卷,华为odE卷,华为od机试真题E卷,华为OD,华为OD机试,华为OD机试真题,华为od机考,华为od机试D卷,华为od机试真题D卷,华为od手撕代码,华为od,华为od机试C卷,华为od e卷,华为2025e卷,od机试,2025E卷,华为OD机试E卷,什么是华为od,华为od介绍,全面了解华为od,2025华为od,如何备战华为od,

正在更新最新华为OD机试2025B卷,提供OJ在线刷题 197

提升 Spring Boot 吞吐量的 7 个神技,让你的项目飞起来!

点击关注公众号,Java干货及时送达一、异步执行实现方式二种:使用异步注解 @aysnc、启动类:添加 @EnableAsync 注解JDK 8 本身有一个非常好用的 Future 类——CompletableFuture@AllArgsConstructor publicclassAskThreadimplementsRunnable{ private...

Java技术栈,分享最主流的Java技术 376

AI上推荐 之 逻辑回归模型与GBDT+LR(特征工程模型化的开端)

1. 前言 随着信息技术和互联网的发展, 我们已经步入了一个信息过载的时代,这个时代,无论是信息消费者还是信息生产者都遇到了很大的挑战: 信息消费者:如何从大量的信息中找到自己感兴趣的信息? 信息生产者:如何让自己生产的信息脱颖而出, 受到广大用户的关注? 为了解决这个矛盾, 推荐系统应时而生, 并飞速前进,在用户和信息之间架起了一道桥梁,一方面帮助用户发现对自己有价值的信息, 一方面让信息能够展现在对它感兴趣的用户前面。 推荐系统近几年有了深度学习的助推发展之势迅猛, 从前深度学习的传统推荐模型(协

Miracle8070 8255
上一篇: Spring Boot + Disruptor = 王炸!!
下一篇: eBPF 是用来干什么的?
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值