今天这篇文章介绍七种常见的SpringBoot性能优化方向。1。异步执行 实现方式二种:使用异步注解Aysnc、启动类:添加EnableAsync注解。JDK8本身有一个非常好用的Future类CompletableFuture。AllArgsConstructorpublicclassAskThreadimplementsRunnable{privateCompletableFutureIntegerrenull;publicvoidrun(){intmyRe0;try{myRere。get()re。get();}catch(Exceptione){e。printStackTrace();}System。out。println(myRe);}publicstaticvoidmain(String〔〕args)throwsInterruptedException{finalCompletableFutureIntegerfuturenewCompletableFuture();newThread(newAskThread(future))。start();模拟长时间的计算过程Thread。sleep(1000);告知完成结果future。complete(60);}} 在该示例中,启动一个线程,此时AskThread对象还没有拿到它需要的数据,执行到myRere。get()re。get()会阻塞。 我们用休眠1秒来模拟一个长时间的计算过程,并将计算结果告诉future执行结果,AskThread线程将会继续执行。publicclassCalc{publicstaticIntegercalc(Integerpara){try{模拟一个长时间的执行Thread。sleep(1000);}catch(InterruptedExceptione){e。printStackTrace();}returnparapara;}publicstaticvoidmain(String〔〕args)throwsExecutionException,InterruptedException{finalCompletableFutureVoidfutureCompletableFuture。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(Runnablerunnable),一般我们在优化Controller时,使用这个方法比较多。 这两个方法如果在不指定线程池的情况下,都是在ForkJoinPool。common线程池中执行,而这个线程池中的所有线程都是Daemon(守护)线程,所以,当主线程结束时,这些线程无论执行完毕都会退出系统。 核心代码:CompletableFuture。runAsync(()this。afterBetProcessor(betRequest,betDetailResult,appUser,id)); 异步调用使用Callable来实现:RestControllerpublicclassHelloController{privatestaticfinalLoggerloggerLoggerFactory。getLogger(HelloController。class);AutowiredprivateHelloServicehello;GetMapping(helloworld)publicStringhelloWorldController(){returnhello。sayHello();}异步调用restful当controller返回值是Callable的时候,springmvc就会启动一个线程将Callable交给TaskExecutor去处理然后DispatcherServlet还有所有的spring拦截器都退出主线程,然后把response保持打开的状态当Callable执行结束之后,springmvc就会重新启动分配一个request请求,然后DispatcherServlet就重新调用和处理Callable异步执行的返回结果,然后返回视图returnGetMapping(hello)publicCallableStringhelloController(){logger。info(Thread。currentThread()。getName()进入helloController方法);CallableStringcallablenewCallableString(){OverridepublicStringcall()throwsException{logger。info(Thread。currentThread()。getName()进入call方法);Stringsayhello。sayHello();logger。info(Thread。currentThread()。getName()从helloService方法返回);returnsay;}};logger。info(Thread。currentThread()。getName()从helloController方法返回);returncallable;}} 异步调用的方式WebAsyncTask:RestControllerpublicclassHelloController{privatestaticfinalLoggerloggerLoggerFactory。getLogger(HelloController。class);AutowiredprivateHelloServicehello;带超时时间的异步请求通过WebAsyncTask自定义客户端超时间returnGetMapping(world)publicWebAsyncTaskStringworldController(){logger。info(Thread。currentThread()。getName()进入helloController方法);3s钟没返回,则认为超时WebAsyncTaskStringwebAsyncTasknewWebAsyncTask(3000,newCallableString(){OverridepublicStringcall()throwsException{logger。info(Thread。currentThread()。getName()进入call方法);Stringsayhello。sayHello();logger。info(Thread。currentThread()。getName()从helloService方法返回);returnsay;}});logger。info(Thread。currentThread()。getName()从helloController方法返回);webAsyncTask。onCompletion(newRunnable(){Overridepublicvoidrun(){logger。info(Thread。currentThread()。getName()执行完毕);}});webAsyncTask。onTimeout(newCallableString(){OverridepublicStringcall()throwsException{logger。info(Thread。currentThread()。getName()onTimeout);超时的时候,直接抛异常,让外层统一处理超时异常thrownewTimeoutException(调用超时);}});returnwebAsyncTask;}异步调用,异常处理,详细的处理流程见MyExceptionHandler类returnGetMapping(exception)publicWebAsyncTaskStringexceptionController(){logger。info(Thread。currentThread()。getName()进入helloController方法);CallableStringcallablenewCallableString(){OverridepublicStringcall()throwsException{logger。info(Thread。currentThread()。getName()进入call方法);thrownewTimeoutException(调用超时!);}};logger。info(Thread。currentThread()。getName()从helloController方法返回);returnnewWebAsyncTask(20000,callable);}}2。增加内嵌Tomcat的最大连接数 代码如下:ConfigurationpublicclassTomcatConfig{BeanpublicConfigurableServletWebServerFactorywebServerFactory(){TomcatServletWebServerFactorytomcatFactorynewTomcatServletWebServerFactory();tomcatFactory。addConnectorCustomizers(newMyTomcatConnectorCustomizer());tomcatFactory。setPort(8005);tomcatFactory。setContextPath(apig);returntomcatFactory;}classMyTomcatConnectorCustomizerimplementsTomcatConnectorCustomizer{publicvoidcustomize(Connectorconnector){Http11NioProtocolprotocol(Http11NioProtocol)connector。getProtocolHandler();设置最大连接数protocol。setMaxConnections(20000);设置最大线程数protocol。setMaxThreads(2000);protocol。setConnectionTimeout(30000);}}}3。使用ComponentScan() 使用ComponentScan()定位扫包比SpringBootApplication扫包更快。4。默认Tomcat容器改为Undertow 默认Tomcat容器改为Undertow(Jboss下的服务器,Tomcat吞吐量5000,Undertow吞吐量8000)exclusionsexclusiongroupIdorg。springframework。bootgroupIdspringbootstartertomcatartifactIdexclusionexclusions 改为:dependencygroupIdorg。springframework。bootgroupIdspringbootstarterundertowartifactIddependency5。使用BufferedWriter进行缓冲 这里不给大家举例,可自行尝试。6。Deferred方式实现异步调用 代码如下:RestControllerpublicclassAsyncDeferredController{privatefinalLoggerloggerLoggerFactory。getLogger(this。getClass());privatefinalLongTimeTasktaskService;AutowiredpublicAsyncDeferredController(LongTimeTasktaskService){this。taskServicetaskService;}GetMapping(deferred)publicDeferredResultStringexecuteSlowTask(){logger。info(Thread。currentThread()。getName()进入executeSlowTask方法);DeferredResultStringdeferredResultnewDeferredResult();调用长时间执行任务taskService。execute(deferredResult);当长时间任务中使用deferred。setResult(world);这个方法时,会从长时间任务中返回,继续controller里面的流程logger。info(Thread。currentThread()。getName()从executeSlowTask方法返回);超时的回调方法deferredResult。onTimeout(newRunnable(){Overridepublicvoidrun(){logger。info(Thread。currentThread()。getName()onTimeout);返回超时信息deferredResult。setErrorResult(timeout!);}});处理完成的回调方法,无论是超时还是处理成功,都会进入这个回调方法deferredResult。onCompletion(newRunnable(){Overridepublicvoidrun(){logger。info(Thread。currentThread()。getName()onCompletion);}});returndeferredResult;}}7。异步调用可以使用AsyncHandlerInterceptor进行拦截 代码如下:ComponentpublicclassMyAsyncHandlerInterceptorimplementsAsyncHandlerInterceptor{privatestaticfinalLoggerloggerLoggerFactory。getLogger(MyAsyncHandlerInterceptor。class);OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{returntrue;}OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{HandlerMethodhandlerMethod(HandlerMethod)handler;logger。info(Thread。currentThread()。getName()服务调用完成,返回结果给客户端);}OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{if(null!ex){System。out。println(发生异常:ex。getMessage());}}OverridepublicvoidafterConcurrentHandlingStarted(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{拦截之后,重新写回数据,将原来的helloworld换成如下字符串Stringrespmynameischhliu!;response。setContentLength(resp。length());response。getOutputStream()。write(resp。getBytes());logger。info(Thread。currentThread()。getName()进入afterConcurrentHandlingStarted方法);}}