日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Spring Boot 性能太差?試試這幾招!

來源: 責編: 時間:2024-06-05 17:46:29 154觀看
導讀今天這篇文章介紹七種常見的Spring Boot 性能優化方向。1. 異步執行實現方式二種:使用異步注解 @Aysnc、啟動類:添加 @EnableAsync 注解。JDK 8 本身有一個非常好用的 Future 類——CompletableFuture。@AllArgsConstru

今天這篇文章介紹七種常見的Spring Boot 性能優化方向。z5H28資訊網——每日最新資訊28at.com

1. 異步執行

實現方式二種:z5H28資訊網——每日最新資訊28at.com

  • 使用異步注解 @Aysnc、啟動類:添加 @EnableAsync 注解。
  • 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() 會阻塞。z5H28資訊網——每日最新資訊28at.com

我們用休眠 1 秒來模擬一個長時間的計算過程,并將計算結果告訴 future 執行結果,AskThread 線程將會繼續執行。z5H28資訊網——每日最新資訊28at.com

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() 方法中,它會在一個新線程中,執行傳入的參數。z5H28資訊網——每日最新資訊28at.com

在這里它會執行 calc() 方法,這個方法可能是比較慢的,但這并不影響 CompletableFuture 實例的構造速度,supplyAsync() 會立即返回。z5H28資訊網——每日最新資訊28at.com

而返回的 CompletableFuture 實例就可以作為這次調用的契約,在將來任何場合,用于獲得最終的計算結果。z5H28資訊網——每日最新資訊28at.com

supplyAsync 用于提供返回值的情況,CompletableFuture 還有一個不需要返回值的異步調用方法 runAsync(Runnable runnable),一般我們在優化 Controller 時,使用這個方法比較多。z5H28資訊網——每日最新資訊28at.com

這兩個方法如果在不指定線程池的情況下,都是在 ForkJoinPool.common 線程池中執行,而這個線程池中的所有線程都是 Daemon(守護)線程,所以,當主線程結束時,這些線程無論執行完畢都會退出系統。z5H28資訊網——每日最新資訊28at.com

核心代碼:z5H28資訊網——每日最新資訊28at.com

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

異步調用使用 Callable 來實現:z5H28資訊網——每日最新資訊28at.com

@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:z5H28資訊網——每日最新資訊28at.com

@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);      }    }

2. 增加內嵌 Tomcat 的最大連接數

代碼如下:z5H28資訊網——每日最新資訊28at.com

@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);          }      }    }

3. 使用 @ComponentScan()

使用 @ComponentScan() 定位掃包比 @SpringBootApplication 掃包更快。z5H28資訊網——每日最新資訊28at.com

4. 默認 Tomcat 容器改為 Undertow

默認 Tomcat 容器改為 Undertow(Jboss 下的服務器,Tomcat 吞吐量 5000,Undertow 吞吐量 8000)z5H28資訊網——每日最新資訊28at.com

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

改為:z5H28資訊網——每日最新資訊28at.com

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

5. 使用 BufferedWriter 進行緩沖

這里不給大家舉例,可自行嘗試。z5H28資訊網——每日最新資訊28at.com

6. Deferred 方式實現異步調用

代碼如下:z5H28資訊網——每日最新資訊28at.com

@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;      }  }

7. 異步調用可以使用 AsyncHandlerInterceptor 進行攔截

代碼如下:z5H28資訊網——每日最新資訊28at.com

@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方法");   }    }

z5H28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-92174-0.htmlSpring Boot 性能太差?試試這幾招!

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 團隊代碼風格混亂?Spotless 幫你搞定!

下一篇: 現在停止濫用useMemo吧!

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 崇仁县| 平阴县| 克拉玛依市| 襄汾县| 五家渠市| 宁津县| 淮滨县| 佳木斯市| 上杭县| 德化县| 文水县| 九寨沟县| 乡城县| 饶阳县| 崇仁县| 广安市| 枣强县| 北京市| 通河县| 双柏县| 新沂市| 兴仁县| 淳安县| 金昌市| 静安区| 汕头市| 黔西| 阜阳市| 民丰县| 格尔木市| 乌海市| 新昌县| 卓资县| 上蔡县| 志丹县| 西华县| 马山县| 镇江市| 志丹县| 菏泽市| 河源市|