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

當(dāng)前位置:首頁 > 科技  > 軟件

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

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

今天這篇文章介紹七種常見的Spring Boot 性能優(yōu)化方向。zDw28資訊網(wǎng)——每日最新資訊28at.com

1. 異步執(zhí)行

實現(xiàn)方式二種:zDw28資訊網(wǎng)——每日最新資訊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);          //告知完成結(jié)果          future.complete(60);      }  }

在該示例中,啟動一個線程,此時 AskThread 對象還沒有拿到它需要的數(shù)據(jù),執(zhí)行到 myRe = re.get() * re.get() 會阻塞。zDw28資訊網(wǎng)——每日最新資訊28at.com

我們用休眠 1 秒來模擬一個長時間的計算過程,并將計算結(jié)果告訴 future 執(zhí)行結(jié)果,AskThread 線程將會繼續(xù)執(zhí)行。zDw28資訊網(wǎng)——每日最新資訊28at.com

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<Void> future = CompletableFuture.supplyAsync(() -> calc(50))                  .thenApply((i) -> Integer.toString(i))                  .thenApply((str) -> "/"" + str + "/"")                  .thenAccept(System.out::println);          future.get();      }  }

CompletableFuture.supplyAsync 方法構(gòu)造一個 CompletableFuture 實例,在 supplyAsync() 方法中,它會在一個新線程中,執(zhí)行傳入的參數(shù)。zDw28資訊網(wǎng)——每日最新資訊28at.com

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

而返回的 CompletableFuture 實例就可以作為這次調(diào)用的契約,在將來任何場合,用于獲得最終的計算結(jié)果。zDw28資訊網(wǎng)——每日最新資訊28at.com

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

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

核心代碼:zDw28資訊網(wǎng)——每日最新資訊28at.com

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

異步調(diào)用使用 Callable 來實現(xiàn):zDw28資訊網(wǎng)——每日最新資訊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();      }        /**       * 異步調(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<String> helloController() {          logger.info(Thread.currentThread().getName() + " 進(jìn)入helloController方法");          Callable<String> callable = new Callable<String>() {                @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:zDw28資訊網(wǎng)——每日最新資訊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() + " 進(jìn)入helloController方法");            // 3s鐘沒返回,則認(rèn)為超時          WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(3000, new Callable<String>() {                @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<String>() {                @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<String> exceptionController() {          logger.info(Thread.currentThread().getName() + " 進(jìn)入helloController方法");          Callable<String> callable = new Callable<String>() {                @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);      }    }

2. 增加內(nèi)嵌 Tomcat 的最大連接數(shù)

代碼如下:zDw28資訊網(wǎng)——每日最新資訊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();              //設(shè)置最大連接數(shù)              protocol.setMaxConnections(20000);              //設(shè)置最大線程數(shù)              protocol.setMaxThreads(2000);              protocol.setConnectionTimeout(30000);          }      }    }

3. 使用 @ComponentScan()

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

4. 默認(rèn) Tomcat 容器改為 Undertow

默認(rèn) Tomcat 容器改為 Undertow(Jboss 下的服務(wù)器,Tomcat 吞吐量 5000,Undertow 吞吐量 8000)zDw28資訊網(wǎng)——每日最新資訊28at.com

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

改為:zDw28資訊網(wǎng)——每日最新資訊28at.com

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

5. 使用 BufferedWriter 進(jìn)行緩沖

這里不給大家舉例,可自行嘗試。zDw28資訊網(wǎng)——每日最新資訊28at.com

6. Deferred 方式實現(xiàn)異步調(diào)用

代碼如下:zDw28資訊網(wǎng)——每日最新資訊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() + "進(jìn)入executeSlowTask方法");          DeferredResult<String> 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;      }  }

7. 異步調(diào)用可以使用 AsyncHandlerInterceptor 進(jìn)行攔截

代碼如下:zDw28資訊網(wǎng)——每日最新資訊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()+ "服務(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 {      // 攔截之后,重新寫回數(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方法");   }    }

zDw28資訊網(wǎng)——每日最新資訊28at.com

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

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

上一篇: 團隊代碼風(fēng)格混亂?Spotless 幫你搞定!

下一篇: 現(xiàn)在停止濫用useMemo吧!

標(biāo)簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 鄂州市| 松江区| 墨玉县| 专栏| 临江市| 洛南县| 富民县| 都昌县| 甘孜县| 济源市| 江山市| 精河县| 栾川县| 汤阴县| 永登县| 宜兴市| 绥德县| 武冈市| 东安县| 黑龙江省| 永春县| 若羌县| 财经| 洛川县| 岑巩县| 永安市| 东安县| 武平县| 滨州市| 二连浩特市| 县级市| 康马县| 石家庄市| 金沙县| 高尔夫| 盐津县| 木兰县| 抚顺县| 延长县| 漳州市| 思茅市|