<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          7種方式,教你提升 SpringBoot 項目的吞吐量

          共 9678字,需瀏覽 20分鐘

           ·

          2022-03-23 12:02

          點擊關注公眾號,Java干貨及時送達??


          來源:xhcom.blog.csdn.net/article/details/88046026

          一、異步執(zhí)行

          實現(xiàn)方式二種:

          1. 使用異步注解@aysnc、啟動類:添加@EnableAsync注解
          2. JDK 8本身有一個非常好用的Future類——CompletableFuture
          @AllArgsConstructor
          public?class?AskThread?implements?Runnable{
          ????private?CompletableFuture?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?future?=?new?CompletableFuture<>();
          ????????new?Thread(new?AskThread(future)).start();
          ????????//模擬長時間的計算過程
          ????????Thread.sleep(1000);
          ????????//告知完成結果
          ????????future.complete(60);
          ????}
          }

          在該示例中,啟動一個線程,此時AskThread對象還沒有拿到它需要的數(shù)據(jù),執(zhí)行到 myRe = re.get() * re.get()會阻塞。我們用休眠1秒來模擬一個長時間的計算過程,并將計算結果告訴future執(zhí)行結果,AskThread線程將會繼續(xù)執(zhí)行。

          public?class?Calc?{
          ????public?static?Integer?calc(Integer?para)?{
          ????????try?{
          ????????????//模擬一個長時間的執(zhí)行
          ????????????Thread.sleep(1000);
          ????????}?catch?(InterruptedException?e)?{
          ????????????e.printStackTrace();
          ????????}
          ????????return?para?*?para;
          ????}

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

          CompletableFuture.supplyAsync方法構造一個CompletableFuture實例,在supplyAsync()方法中,它會在一個新線程中,執(zhí)行傳入的參數(shù)。在這里它會執(zhí)行calc()方法,這個方法可能是比較慢的,但這并不影響CompletableFuture實例的構造速度,supplyAsync()會立即返回。而返回的CompletableFuture實例就可以作為這次調用的契約,在將來任何場合,用于獲得最終的計算結果。

          supplyAsync用于提供返回值的情況,CompletableFuture還有一個不需要返回值的異步調用方法runAsync(Runnable runnable),一般我們在優(yōu)化Controller時,使用這個方法比較多。這兩個方法如果在不指定線程池的情況下,都是在ForkJoinPool.common線程池中執(zhí)行,而這個線程池中的所有線程都是Daemon(守護)線程,所以,當主線程結束時,這些線程無論執(zhí)行完畢都會退出系統(tǒng)。

          核心代碼:

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

          異步調用使用Callable來實現(xiàn)

          @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保持打開的狀態(tài)?
          ?????*?當Callable執(zhí)行結束之后,springmvc就會重新啟動分配一個request請求,然后DispatcherServlet就重新?
          ?????*?調用和處理Callable異步執(zhí)行的返回結果,?然后返回視圖?
          ?????*??
          ?????*?@return?
          ?????*/
          ??
          ????@GetMapping("/hello")??
          ????public?Callable?helloController()?{??
          ????????logger.info(Thread.currentThread().getName()?+?"?進入helloController方法");??
          ????????Callable?callable?=?new?Callable()?{??
          ??
          ????????????@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?worldController()?{??
          ????????logger.info(Thread.currentThread().getName()?+?"?進入helloController方法");??
          ??
          ????????//?3s鐘沒返回,則認為超時??
          ????????WebAsyncTask?webAsyncTask?=?new?WebAsyncTask<>(3000,?new?Callable()?{??
          ??
          ????????????@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()?+?"?執(zhí)行完畢");??
          ????????????}??
          ????????});??
          ??
          ????????webAsyncTask.onTimeout(new?Callable()?{??
          ??
          ????????????@Override??
          ????????????public?String?call()?throws?Exception?{??
          ????????????????logger.info(Thread.currentThread().getName()?+?"?onTimeout");??
          ????????????????//?超時的時候,直接拋異常,讓外層統(tǒng)一處理超時異常??
          ????????????????throw?new?TimeoutException("調用超時");??
          ????????????}??
          ????????});??
          ????????return?webAsyncTask;??
          ????}??
          ??
          ????/**?
          ?????*?異步調用,異常處理,詳細的處理流程見MyExceptionHandler類?
          ?????*??
          ?????*?@return?
          ?????*/
          ??
          ????@GetMapping("/exception")??
          ????public?WebAsyncTask?exceptionController()?{??
          ????????logger.info(Thread.currentThread().getName()?+?"?進入helloController方法");??
          ????????Callable?callable?=?new?Callable()?{??
          ??
          ????????????@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);??
          ????}??
          ??
          }??
          二、增加內嵌Tomcat的最大連接數(shù)
          @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();
          ????????????//設置最大連接數(shù)???????????????
          ????????????protocol.setMaxConnections(20000);
          ????????????//設置最大線程數(shù)???????????????
          ????????????protocol.setMaxThreads(2000);
          ????????????protocol.setConnectionTimeout(30000);
          ????????}
          ????}

          }
          三、使用@ComponentScan()定位掃包比@SpringBootApplication掃包更快
          四、默認tomcat容器改為Undertow(Jboss下的服務器,Tomcat吞吐量5000,Undertow吞吐量8000)
          <exclusions>
          ??<exclusion>
          ?????<groupId>org.springframework.bootgroupId>
          ?????<artifactId>spring-boot-starter-tomcatartifactId>
          ??exclusion>
          exclusions>

          改為:

          <dependency>
          ??<groupId>org.springframework.bootgroupId>
          ??<artifactId>spring-boot-starter-undertowartifactId>
          dependency>
          五、使用 BufferedWriter 進行緩沖
          六、Deferred方式實現(xiàn)異步調用
          @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?executeSlowTask()?{
          ????????logger.info(Thread.currentThread().getName()?+?"進入executeSlowTask方法");
          ????????DeferredResult?deferredResult?=?new?DeferredResult<>();
          ????????//?調用長時間執(zhí)行任務
          ????????taskService.execute(deferredResult);
          ????????//?當長時間任務中使用deferred.setResult("world");這個方法時,會從長時間任務中返回,繼續(xù)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("發(fā)生異常:"+ex.getMessage());
          ??}
          ?}
          ?
          ?@Override
          ?public?void?afterConcurrentHandlingStarted(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler)
          ???throws?Exception?
          {
          ??
          ??//?攔截之后,重新寫回數(shù)據(jù),將原來的hello?world換成如下字符串
          ??String?resp?=?"my?name?is?chhliu!";
          ??response.setContentLength(resp.length());
          ??response.getOutputStream().write(resp.getBytes());
          ??
          ??logger.info(Thread.currentThread().getName()?+?"?進入afterConcurrentHandlingStarted方法");
          ?}
          ?
          }
          參考
          • https://my.oschina.net/u/3768341/blog/3001731
          • https://blog.csdn.net/liuchuanhong1/article/details/78744138

          1.?過濾請求絕技 !布隆過濾器與布谷鳥過濾器

          2.?最新 955 不加班的公司名單(2022版)

          3.?7000 字 + 21 圖,微服務架構概述

          4.?JetBrains 官宣支持烏克蘭,制裁俄羅斯...

          最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構等等。

          獲取方式:點“在看”,關注公眾號并回復?Java?領取,更多內容陸續(xù)奉上。

          PS:因公眾號平臺更改了推送規(guī)則,如果不想錯過內容,記得讀完點一下在看,加個星標,這樣每次新文章推送才會第一時間出現(xiàn)在你的訂閱列表里。

          “在看”支持小哈呀,謝謝啦??

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产一线二线在线观看 | 日本特级黄色电影免费看 | www.水蜜桃视频 | 婷婷乱伦电影 | 天天插夜夜操 |