<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 項(xiàng)目的吞吐量

          共 9488字,需瀏覽 19分鐘

           ·

          2022-04-07 14:58


          作者:灬點(diǎn)點(diǎn)

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



          步執(zhí)行

          實(shí)現(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();
          ????????//模擬長時間的計(jì)算過程
          ????????Thread.sleep(1000);
          ????????//告知完成結(jié)果
          ????????future.complete(60);
          ????}
          }

          在該示例中,啟動一個線程,此時AskThread對象還沒有拿到它需要的數(shù)據(jù),執(zhí)行到myRe = re.get() * re.get()會阻塞。我們用休眠1秒來模擬一個長時間的計(jì)算過程,并將計(jì)算結(jié)果告訴future執(zhí)行結(jié)果,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方法構(gòu)造一個CompletableFuture實(shí)例,在supplyAsync()方法中,它會在一個新線程中,執(zhí)行傳入的參數(shù)。在這里它會執(zhí)行calc()方法,這個方法可能是比較慢的,但這并不影響CompletableFuture實(shí)例的構(gòu)造速度,supplyAsync()會立即返回。而返回的CompletableFuture實(shí)例就可以作為這次調(diào)用的契約,在將來任何場合,用于獲得最終的計(jì)算結(jié)果。

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

          核心代碼:

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

          異步調(diào)用使用Callable來實(shí)現(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();??
          ????}??
          ??
          ????/**?
          ?????*?異步調(diào)用restful?
          ?????*?當(dāng)controller返回值是Callable的時候,springmvc就會啟動一個線程將Callable交給TaskExecutor去處理?
          ?????*?然后DispatcherServlet還有所有的spring攔截器都退出主線程,然后把response保持打開的狀態(tài)?
          ?????*?當(dāng)Callable執(zhí)行結(jié)束之后,springmvc就會重新啟動分配一個request請求,然后DispatcherServlet就重新?
          ?????*?調(diào)用和處理Callable異步執(zhí)行的返回結(jié)果,?然后返回視圖?
          ?????*??
          ?????*?@return?
          ?????*/
          ??
          ????@GetMapping("/hello")??
          ????public?Callable?helloController()?{??
          ????????logger.info(Thread.currentThread().getName()?+?"?進(jìn)入helloController方法");??
          ????????Callable?callable?=?new?Callable()?{??
          ??
          ????????????@Override??
          ????????????public?String?call()?throws?Exception?{??
          ????????????????logger.info(Thread.currentThread().getName()?+?"?進(jìn)入call方法");??
          ????????????????String?say?=?hello.sayHello();??
          ????????????????logger.info(Thread.currentThread().getName()?+?"?從helloService方法返回");??
          ????????????????return?say;??
          ????????????}??
          ????????};??
          ????????logger.info(Thread.currentThread().getName()?+?"?從helloController方法返回");??
          ????????return?callable;??
          ????}??
          }??

          異步調(diào)用的方式 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()?+?"?進(jìn)入helloController方法");??
          ??
          ????????//?3s鐘沒返回,則認(rèn)為超時??
          ????????WebAsyncTask?webAsyncTask?=?new?WebAsyncTask<>(3000,?new?Callable()?{??
          ??
          ????????????@Override??
          ????????????public?String?call()?throws?Exception?{??
          ????????????????logger.info(Thread.currentThread().getName()?+?"?進(jìn)入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("調(diào)用超時");??
          ????????????}??
          ????????});??
          ????????return?webAsyncTask;??
          ????}??
          ??
          ????/**?
          ?????*?異步調(diào)用,異常處理,詳細(xì)的處理流程見MyExceptionHandler類?
          ?????*??
          ?????*?@return?
          ?????*/
          ??
          ????@GetMapping("/exception")??
          ????public?WebAsyncTask?exceptionController()?{??
          ????????logger.info(Thread.currentThread().getName()?+?"?進(jìn)入helloController方法");??
          ????????Callable?callable?=?new?Callable()?{??
          ????????????@Override??
          ????????????public?String?call()?throws?Exception?{??
          ????????????????logger.info(Thread.currentThread().getName()?+?"?進(jìn)入call方法");??
          ????????????????throw?new?TimeoutException("調(diào)用超時!");??
          ????????????}??
          ????????};??
          ????????logger.info(Thread.currentThread().getName()?+?"?從helloController方法返回");??
          ????????return?new?WebAsyncTask<>(20000,?callable);??
          ????}??
          }??
          二、增加內(nèi)嵌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è)置最大連接數(shù)???????????????
          ????????????protocol.setMaxConnections(20000);
          ????????????//設(shè)置最大線程數(shù)???????????????
          ????????????protocol.setMaxThreads(2000);
          ????????????protocol.setConnectionTimeout(30000);
          ????????}
          ????}
          }
          三、使用@ComponentScan()定位掃包比@SpringBootApplication掃包更快
          四、默認(rèn)tomcat容器改為Undertow(Jboss下的服務(wù)器,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 進(jìn)行緩沖
          六、Deferred方式實(shí)現(xiàn)異步調(diào)用
          @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()?+?"進(jìn)入executeSlowTask方法");
          ????????DeferredResult?deferredResult?=?new?DeferredResult<>();
          ????????//?調(diào)用長時間執(zhí)行任務(wù)
          ????????taskService.execute(deferredResult);
          ????????//?當(dāng)長時間任務(wù)中使用deferred.setResult("world");這個方法時,會從長時間任務(wù)中返回,繼續(xù)controller里面的流程
          ????????logger.info(Thread.currentThread().getName()?+?"從executeSlowTask方法返回");
          ????????//?超時的回調(diào)方法
          ????????deferredResult.onTimeout(new?Runnable(){
          ??
          ???@Override
          ???public?void?run()?{
          ????logger.info(Thread.currentThread().getName()?+?"?onTimeout");
          ????//?返回超時信息
          ????deferredResult.setErrorResult("time?out!");
          ???}
          ??});
          ????????
          ????????//?處理完成的回調(diào)方法,無論是超時還是處理成功,都會進(jìn)入這個回調(diào)方法
          ????????deferredResult.onCompletion(new?Runnable(){
          ??
          ???@Override
          ???public?void?run()?{
          ????logger.info(Thread.currentThread().getName()?+?"?onCompletion");
          ???}
          ??});??
          ????????return?deferredResult;
          ????}
          }
          七、異步調(diào)用可以使用AsyncHandlerInterceptor進(jìn)行攔截
          @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()+?"服務(wù)調(diào)用完成,返回結(jié)果給客戶端");
          ?}
          ?
          ?@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?
          {
          ??
          ??//?攔截之后,重新寫回?cái)?shù)據(jù),將原來的hello?world換成如下字符串
          ??String?resp?=?"my?name?is?chhliu!";
          ??response.setContentLength(resp.length());
          ??response.getOutputStream().write(resp.getBytes());
          ??logger.info(Thread.currentThread().getName()?+?"?進(jìn)入afterConcurrentHandlingStarted方法");
          ?}?
          }
          參考
          • https://my.oschina.net/u/3768341/blog/3001731
          • https://blog.csdn.net/liuchuanhong1/article/details/78744138


          如有文章對你有幫助,

          在看”和轉(zhuǎn)發(fā)是對我最大的支持!

          1、SpringBoot + Elasticsearch7.6 實(shí)現(xiàn)查詢及高亮分詞查詢,超級詳細(xì)!
          2、MyBatis 二級緩存 關(guān)聯(lián)刷新實(shí)現(xiàn)
          3、一個很酷的圖床系統(tǒng)(自帶鑒黃功能)
          4、用了 HTTPS 就一定安全嗎?
          5、單點(diǎn)登錄系統(tǒng)用幾張漫畫就解釋了 。。。


          點(diǎn)分享

          點(diǎn)收藏

          點(diǎn)點(diǎn)贊

          點(diǎn)在看

          瀏覽 23
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  日韩大尺度视频 | 怕怕视频2017 | 韵韵阳具 | a 视频在线观看 | 亚欧洲精品在线视频 |