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

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

優(yōu)化SpringBoot吞吐量的七個高效策略

來源: 責(zé)編: 時間:2024-06-28 17:15:11 127觀看
導(dǎo)讀1、異步執(zhí)行實現(xiàn)方式二種:使用異步注解 @aysnc、啟動類:添加 @EnableAsync 注解JDK 8 本身有一個非常好用的 Future 類——CompletableFuture@AllArgsConstructorpublic class AskThread implements Runnable{ priva

1、異步執(zhí)行se028資訊網(wǎng)——每日最新資訊28at.com

實現(xiàn)方式二種:se028資訊網(wǎng)——每日最新資訊28at.com

  • 使用異步注解 @aysnc、啟動類:添加 @EnableAsync 注解
  • JDK 8 本身有一個非常好用的 Future 類——CompletableFuture
@AllArgsConstructorpublic 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() 會阻塞。se028資訊網(wǎng)——每日最新資訊28at.com

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

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

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

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

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

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

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

異步調(diào)用使用 Callable 來實現(xiàn):se028資訊網(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:se028資訊網(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);    }}


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

2、增加內(nèi)嵌 Tomcat 的最大連接數(shù)se028資訊網(wǎng)——每日最新資訊28at.com

代碼如下:se028資訊網(wǎng)——每日最新資訊28at.com

@Configurationpublic 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()se028資訊網(wǎng)——每日最新資訊28at.com

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

4、默認(rèn) Tomcat 容器改為 Undertowse028資訊網(wǎng)——每日最新資訊28at.com

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

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

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

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

5、使用 BufferedWriter 進(jìn)行緩沖se028資訊網(wǎng)——每日最新資訊28at.com

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

6、Deferred 方式實現(xiàn)異步調(diào)用se028資訊網(wǎng)——每日最新資訊28at.com

代碼如下:se028資訊網(wǎng)——每日最新資訊28at.com

@RestControllerpublic 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)行攔截se028資訊網(wǎng)——每日最新資訊28at.com

代碼如下:se028資訊網(wǎng)——每日最新資訊28at.com

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


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

本文鏈接:http://www.www897cc.com/showinfo-26-97290-0.html優(yōu)化SpringBoot吞吐量的七個高效策略

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

上一篇: 列表大揭秘:一文掌握 Python 列表的高級玩法

下一篇: C#/.NET這些實用的技巧和知識點你都知道嗎?

標(biāo)簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 新蔡县| 宁德市| 张家港市| 胶州市| 固原市| 余江县| 保康县| 江陵县| 万荣县| 浮山县| 定安县| 北安市| 奎屯市| 舞阳县| 西宁市| 木兰县| 绵阳市| 虹口区| 灵宝市| 乐昌市| 子长县| 吉林省| 万全县| 焦作市| 德州市| 肇庆市| 曲周县| 珠海市| 盐边县| 介休市| 谢通门县| 衢州市| 越西县| 饶平县| 安图县| 鲁甸县| 安宁市| 吉安市| 合川市| 白山市| 深圳市|