<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

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

    VSole2022-03-30 16:44:20

    一、異步執行

    實現方式二種:

    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對象還沒有拿到它需要的數據,執行到myRe = re.get() * re.get()會阻塞。我們用休眠1秒來模擬一個長時間的計算過程,并將計算結果告訴future執行結果,AskThread線程將會繼續執行。

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

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

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

    核心代碼:

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

    異步調用使用Callable來實現

    @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 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() + " 執行完畢");  
                }  
            });  
      
            webAsyncTask.onTimeout(new Callable() {  
                @Override  
                public String call() throws Exception {  
                    logger.info(Thread.currentThread().getName() + " onTimeout");  
                    // 超時的時候,直接拋異常,讓外層統一處理超時異常  
                    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的最大連接數
    @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);
            }
        }
    }
    
    三、使用@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方式實現異步調用
    @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<>();
            // 調用長時間執行任務
            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;
        }
    }
    
    七、異步調用可以使用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("發生異常:"+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方法");
     } 
    }
    
    參考
    • https://my.oschina.net/u/3768341/blog/3001731
    • https://blog.csdn.net/liuchuanhong1/article/details/78744138
    string
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    如果你不是 Java8 的釘子戶,你應該早就發現了:String 類的源碼已經由 char[] 優化為了 byte[] 來存儲字符串內容,為什么要這樣做呢? 開門見山地說,從 char[] 到 byte[],最主要的目的是為了節省字符串占用的內存 。內存占用減少帶來的另外一個好處,就是 GC 次數也會減少。
    Adobe已經發布了一個名為Stringlifier的開源工具,該工具允許用戶識別任何純文本中隨機生成的字符串,該工具可用于清理日志。Stringlifier工具是用Python編寫的,它使用機器學習來識別插入普通文本中的隨機字符序列。開源工具可用于出于多種目的分析日志,例如研究意外暴露的憑證。Stringlifier能夠在源代碼或配置文件中查找API密鑰,哈希,隨機生成的字符串,包括密碼,日志。Adobe在Github上發布的描述中寫道。
    介紹Runtime 是一系列采用 C++ 語言編寫的功能方法,它實現了大量 JavaScript 運行期間需要的 native 功能。本文分析 Runtime_StringToArray 方法的源碼和重要數據結構,講解 Runtime_StringToArray 方法的觸發條件。
    介紹Runtime 是一系列采用 C++ 語言編寫的功能方法,它實現了大量 JavaScript 運行期間需要的 native 功能。
    通過common-collection相關gadget,想辦法調用org.mozilla.classfile.DefiningClassLoader這個類去加載字節碼。然后通過T3協議的反序列化漏洞發送給待攻擊weblogic服務器。
    舉個例子:但是對于64位的來說 ROPgadget預設的長度是不夠的。所以,我們可以使用ROPgadget --binary ./b --depth 100來加深他的搜索深度。2利用_libc_csu_init制造ROP常規方法我們前面說的利用ROPgadget來尋找,大多都是找到直接設置某個寄存器的rop,當然也可以使用--ropchain這個參數。
    一般情況下類與類之間是相互獨立的,內部類的意思就是打破這種獨立思想,讓一個類成為另一個類的內部信息,和成員變量、成員方法同等級別。「內部類的好處:」把一個類寫在外面和寫在里面最終達到的結果都一樣,那我們為什么還要使用內部類,豈不是多此一舉嗎?
    當被問及網絡間諜是否成功時,愛德華·斯金格表示,他非常有信心地確信,除了國防學院本身,沒有任何其他危害行為。斯金格接受采訪時透露,本次攻擊看起來不像是一次暴力攻擊,但有代價。國防學院立即意識到它可能已成為敵對國家在灰色地帶式網絡攻擊中的目標的可能性。官方迅速采取了行動,對更廣泛的國防部IT網絡沒有影響。
    java安全-02RMI
    2022-03-25 15:35:13
    基礎知識動態代理反射攻擊方式注冊端攻擊服務端java -cp .\ysoserial-master-8eb5
    MISC中常用python腳本
    2021-09-20 20:26:46
    MISC中常用python腳本總結
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类