1. 程式人生 > >Spring Boot 效能優化

Spring Boot 效能優化

Spring 框架給企業軟體開發者提供了常見問題的通用解決方案,包括那些在未來開發中沒有意識到的問題。但是,它構建的 J2EE 專案變得越來越臃腫,逐漸被 Spring Boot 所替代。Spring Boot 讓我們建立和執行專案變得更為迅速,現在已經有越來越多的人使用它。我們已經在幾個專案中使用了 Spring Boot ,今天我們就來一起討論一下如何改進 Spring Boot 應用的效能。

首先,從之前我在開發中遇到的一個問題說起。在一次檢視專案執行日誌的時候,我偶然發現了一個問題,日誌裡顯示這個專案總是載入 Velocity 模板引擎,但實際上這個專案是一個沒有 web 頁面的 REST Service 專案。於是我花了一點時間去尋找產生這個問題的原因,以及如何改進 Spring Boot 應用的效能。在查找了相關的資料後,我得出的結論如下:

元件自動掃描帶來的問題

預設情況下,我們會使用 @SpringBootApplication 註解來自動獲取的應用的配置資訊,但這樣也會給應用帶來一些副作用。使用這個註解後,會觸發自動配置( auto-configuration )和 元件掃描 ( component scanning ),這跟使用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三個註解的作用是一樣的。這樣做給開發帶來方便的同時,也會有兩方面的影響:

1、會導致專案啟動時間變長。當啟動一個大的應用程式,或將做大量的整合測試啟動應用程式時,影響會特別明顯。

2、會載入一些不需要的多餘的例項(beans)。

3、會增加 CPU 消耗。

針對以上兩個情況,我們可以移除 @SpringBootApplication 和 @ComponentScan 兩個註解來禁用元件自動掃描,然後在我們需要的 bean 上進行顯式配置:

// 移除 @SpringBootApplication and @ComponentScan, 用 @EnableAutoConfiguration 來替代
@Configuration
@EnableAutoConfiguration
public class SampleWebUiApplication {

    // ...

    // 用 @Bean 註解明確顯式配置,以便被 Spring 掃描到
    @Bean
    public MessageController messageController(MessageRepository messageRepository) {
        return new MessageController(messageRepository);
    }

如何避免元件自動掃描帶來的問題

我們在上面提到,@SpringBootApplication 註解的作用跟 @EnableAutoConfiguration 註解的作用是相當的,那就意味著它也能帶來上述的三個問題。要避免這些問題,我們就要知道我們需要的元件列表是哪些,可以用 -Ddebug 的方式來幫助我們明確地定位:

mvn spring-boot:run -Ddebug  
…
=========================
AUTO-CONFIGURATION REPORT  
=========================


Positive matches:  
-----------------

   DispatcherServletAutoConfiguration
      - @ConditionalOnClass classes found: org.springframework.web.servlet.DispatcherServlet (OnClassCondition)
      - found web application StandardServletEnvironment (OnWebApplicationCondition)

...

接著拷貝 Positive matches 中列出的資訊:

DispatcherServletAutoConfiguration  
EmbeddedServletContainerAutoConfiguration  
ErrorMvcAutoConfiguration  
HttpEncodingAutoConfiguration  
HttpMessageConvertersAutoConfiguration  
JacksonAutoConfiguration  
JmxAutoConfiguration  
MultipartAutoConfiguration  
ServerPropertiesAutoConfiguration  
PropertyPlaceholderAutoConfiguration  
ThymeleafAutoConfiguration  
WebMvcAutoConfiguration  
WebSocketAutoConfiguration  

然後來更新專案配置,顯式地引入這些元件,引入之後,再執行一下應用確保沒有錯誤發生:

@Configuration
@Import({
        DispatcherServletAutoConfiguration.class,
        EmbeddedServletContainerAutoConfiguration.class,
        ErrorMvcAutoConfiguration.class,
        HttpEncodingAutoConfiguration.class,
        HttpMessageConvertersAutoConfiguration.class,
        JacksonAutoConfiguration.class,
        JmxAutoConfiguration.class,
        MultipartAutoConfiguration.class,
        ServerPropertiesAutoConfiguration.class,
        PropertyPlaceholderAutoConfiguration.class,
        ThymeleafAutoConfiguration.class,
        WebMvcAutoConfiguration.class,
        WebSocketAutoConfiguration.class,
})
public class SampleWebUiApplication {  

在上面的程式碼中,我們可以刪掉我們不需要的元件資訊,來提高應用的效能,比如在我的專案中,不需要 JMX 和 WebSocket 功能,我就刪掉了它們。刪掉之後,再次執行專案,確保一切正常。

將Servlet容器變成Undertow

預設情況下,Spring Boot 使用 Tomcat 來作為內嵌的 Servlet 容器。我們可以啟動專案,然後用 VisualVM 或者 JConsole 來檢視應用所佔的記憶體情況:

以上是我使用 Spring Boot 的預設方式啟動應用後,用 VisualVM 監控到的記憶體的佔用情況:堆記憶體佔用 110M,16 個執行緒被開啟。

可以將 Web 伺服器切換到 Undertow 來提高應用效能 。Undertow 是一個採用 Java 開發的靈活的高效能 Web 伺服器,提供包括阻塞和基於 NIO 的非堵塞機制。Undertow 是紅帽公司的開源產品,是 Wildfly 預設的 Web 伺服器。首先,從依賴資訊裡移除 Tomcat 配置:

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

然後新增 Undertow:

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

啟動專案後,用 VisualVM 監控到的資訊顯示:堆記憶體佔用 90M,13個執行緒被開啟。

總結

這些都是我們在專案開發中使用到的一些優化 Spring Boot 應用的小技巧,對於大的應用效能的提高還是很明顯的。大家可以嘗試一下,然後告訴我們你的測試結果。

文中大部分內容參考英國一個架構師的 部落格 DZone 近期釋出的文章,在此感謝兩位大牛。參考文章及連結:

OneAPM 為您提供端到端的 Java 應用效能解決方案 ,我們支援所有常見的 Java 框架及應用伺服器,助您快速發現系統瓶頸,定位異常根本原因。分鐘級部署,即刻體驗,Java 監控從來沒有如此簡單。想閱讀更多技術文章,請訪問OneAPM 官方技術部落格。