一、SpringBoot啟動過程干預
Spring Boot啟動過程中我們可以實現以下干預工作:
-
修改Spring Boot默認的配置屬性。使用
@ConfigurationProperties
和@EnableConfigurationProperties
注解,可以獲取和修改Spring Boot的配置屬性。 -
加載配置文件。Spring Boot會自動加載application.properties或application.yml等配置文件,我們可以在啟動時加載其他配置文件。
-
自定義bean。我們可以通過
@Component
注解創建自定義的bean以及其他的@SpringBootAnnotation
注解,來實現更靈活的配置和自動化初始化。 -
執行一些初始化邏輯。我們可以對應用程序的數據庫、緩存、MQ等進行初始化,例如創建數據源、初始化緩存等,以確保應用程序正常運行,并且可以通過
ApplicationRunner
和CommandLineRunner
等干預代碼的方式執行這些初始化邏輯。 -
執行一些后置操作。在Spring Boot應用程序停止后執行一些清理工作,例如關閉數據源、釋放緩存等。
這些干預步驟可以在Spring Boot應用程序啟動和停止完成后進行,從而實現更靈活的配置和初始化。
(一)ApplicationContextInitializer擴展
通過實現ApplicationContextInitializer
接口,我們可以在ApplicationContext
創建之前對其進行一些定制化的修改。這個接口定義了一個initialize方法,接受一個ConfigurableApplicationContext
對象作為參數,我們可以在這個方法中對這個對象進行修改和配置。
具體來說,我們可以通過ApplicationContextInitializer
實現以下擴展任務:
-
修改Spring Boot默認的environment屬性。使用
configurableApplicationContext.getEnvironment()
方法獲取到environment對象,從而修改環境變量,例如添加自定義配置文件路徑。 -
添加自定義的PropertySource。使用
environment.getPropertySources().addLast(propertySource)
方法,可以添加自定義的屬性源,從而實現更靈活的配置。 -
注冊自定義bean。使用
configurableApplicationContext.getBeanFactory().registerSingleton(beanName, bean)
方法,可以注冊自定義的bean,從而實現更靈活的依賴注入。
可以添加自定義的ApplicationContextInitializer
實現類,從而擴展應用程序的初始化邏輯。
總之,通過實現ApplicationContextInitializer
接口,可以在Spring Boot應用程序啟動之前對應用程序進行一些初始化定制化的操作,從而滿足開發者對應用程序的特殊需求。
修改Spring Boot默認的environment屬性
修改Spring Boot默認的environment屬性,例如添加自定義配置文件路徑,可以通過實現ApplicationContextInitializer
接口來完成。下面是一個示例代碼,演示如何添加自定義配置文件路徑:
package?org.zyf.javabasic.springextend.runext;import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import?org.springframework.context.ApplicationContextInitializer;
import?org.springframework.context.ConfigurableApplicationContext;
import?org.springframework.core.env.ConfigurableEnvironment;
import?org.springframework.core.env.PropertySource;
import?org.springframework.core.io.support.ResourcePropertySource;import?java.io.IOException;/***?@author?woniu*?@description?修改Spring Boot默認的environment屬性。使用configurableApplicationContext.getEnvironment()方法獲取到environment對象,從而修改環境變量,例如添加自定義配置文件路徑。*/
public?class?InterveneApplicationContextInitializer?implements?ApplicationContextInitializer<ConfigurableApplicationContext>?{@Overridepublic?void?initialize(ConfigurableApplicationContext?configurableApplicationContext)?{ConfigurableEnvironment?environment?=?configurableApplicationContext.getEnvironment();//?添加自定義配置文件路徑try?{ObjectMapper?objectMapper?=?new?ObjectMapper();System.out.println("InterveneApplicationContextInitializer?initialize?:"?+?configurableApplicationContext);environment.getPropertySources().addFirst(new?ResourcePropertySource("classpath:zyftest.properties"));System.out.println("InterveneApplicationContextInitializer?initialize?add?FirstResourcePropertySource??classpath:zyftest.properties");}?catch?(IOException?e)?{e.printStackTrace();}}
}
在上面的代碼中,我們通過getEnvironment()
方法獲取到ConfigurableEnvironment
對象,然后通過getPropertySources()
方法獲取到屬性源,使用addFirst()
方法將自定義的custom.properties
文件的PropertySource
添加到屬性源的首位。這樣,在應用程序啟動時,就會首先加載custom.properties
文件,從而實現了自定義的配置。
需要注意的是,上述代碼中的InterveneApplicationContextInitializer
需要被注冊才能生效。可以通過在src/main/resources/META-INF/spring.factories
文件中指定注冊項的方式來注冊:
org.springframework.context.ApplicationContextInitializer=
org.zyf.javabasic.springextend.runext.InterveneApplicationContextInitializer
添加自定義的PropertySource
添加自定義的PropertySource,可以通過實現ApplicationContextInitializer
接口來完成。下面是一個示例代碼,演示如何添加自定義的PropertySource:
package?org.zyf.javabasic.springextend.runext;import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import?org.springframework.context.ApplicationContextInitializer;
import?org.springframework.context.ConfigurableApplicationContext;
import?org.springframework.core.env.ConfigurableEnvironment;
import?org.springframework.core.env.PropertySource;
import?org.springframework.core.io.support.ResourcePropertySource;import?java.io.IOException;/***?@author?woniu*?@description?添加自定義的PropertySource。使用environment.getPropertySources().addLast(propertySource)方法,可以添加自定義的屬性源,從而實現更靈活的配置。*/
public?class?InterveneApplicationContextInitializer?implements?ApplicationContextInitializer<ConfigurableApplicationContext>?{@Overridepublic?void?initialize(ConfigurableApplicationContext?configurableApplicationContext)?{//?添加自定義的PropertySourcePropertySource<?>?propertySource?=?new?MyPropertySource("myPropertySource");environment.getPropertySources().addLast(propertySource);System.out.println("InterveneApplicationContextInitializer?initialize?add?PropertySource??myPropertySource");}//?自定義PropertySourceprivate?static?class?MyPropertySource?extends?PropertySource<String>?{private?static?final?String?MY_PROPERTY_SOURCE_KEY?=?"my.property.source.key";public?MyPropertySource(String?name)?{super(name);}@Overridepublic?Object?getProperty(String?name)?{if?(MY_PROPERTY_SOURCE_KEY.equals(name))?{return?"myPropertySourceValue";}return?null;}}
}
在上面的代碼中,我們新建了一個名為MyPropertySource的自定義PropertySource,然后在initialize方法中使用environment.getPropertySources().addLast(propertySource)
方法將其添加到Spring環境中。
MyPropertySource中實現了一個用于獲取屬性的getProperty方法,在這個方法中,我們指定了一個名為my.property.source.key
的屬性及其對應的值,這樣就可以通過@Value("${my.property.source.key}")
的方式在應用程序中獲取到它的值了。
需要注意的是,上述代碼中的InterveneApplicationContextInitializer
需要被注冊才能生效。具體如上部分展示,這里不在展示。
注冊自定義bean
注冊自定義Bean,可以通過實現ApplicationContextInitializer
接口來完成。下面是一個示例代碼,演示如何注冊自定義Bean:
package?org.zyf.javabasic.springextend.runext;import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import?org.springframework.context.ApplicationContextInitializer;
import?org.springframework.context.ConfigurableApplicationContext;
import?org.springframework.core.env.ConfigurableEnvironment;
import?org.springframework.core.env.PropertySource;
import?org.springframework.core.io.support.ResourcePropertySource;import?java.io.IOException;/***?@author?woniu*?@description?注冊自定義bean。使用configurableApplicationContext.getBeanFactory().registerSingleton(beanName, bean)方法,可以注冊自定義的bean,從而實現更靈活的依賴注入。*/
public?class?InterveneApplicationContextInitializer?implements?ApplicationContextInitializer<ConfigurableApplicationContext>?{@Overridepublic?void?initialize(ConfigurableApplicationContext?configurableApplicationContext)?{ConfigurableListableBeanFactory?beanFactory?=?configurableApplicationContext.getBeanFactory();//?注冊自定義BeanMyBean?myBean?=?new?MyBean();beanFactory.registerSingleton("myBean",?myBean);System.out.println("InterveneApplicationContextInitializer?initialize?registerSingleton??myBean");}//?自定義Beanprivate?static?class?MyBean?{private?String?name?=?"myBean";public?String?getName()?{return?name;}}
}
在上面的代碼中,我們新建了一個名為MyBean的自定義Bean,然后在initialize方法中使用beanFactory.registerSingleton("myBean", myBean)
方法將其注冊到Spring應用程序上下文中,"myBean"是注冊的bean名稱,myBean是實際的類實例對象。
需要注意的是,上述代碼中的InterveneApplicationContextInitializer
需要被注冊才能生效。具體如上部分展示,這里不在展示。
(二)SpringApplicationRunListener擴展
SpringApplicationRunListener
是Spring Boot的一個事件監聽器,用于在應用程序啟動和停止時執行一些操作。可能需要自定義SpringApplicationRunListener
來執行某些特定操作。下面是一個示例,演示如何擴展SpringApplicationRunListener
以添加自定義操作:
首先,需要實現SpringApplicationRunListener
接口:
package?org.zyf.javabasic.springextend.runext;import?org.springframework.boot.SpringApplication;
import?org.springframework.boot.SpringApplicationRunListener;
import?org.springframework.context.ConfigurableApplicationContext;
import?org.springframework.core.env.ConfigurableEnvironment;/***?@author?woniu*?@description?SpringApplicationRunListener是Spring Boot的一個事件監聽器,用于在應用程序啟動和停止時執行一些操作。*?可能需要自定義SpringApplicationRunListener來執行某些特定操作。*?下面是一個示例,演示如何擴展SpringApplicationRunListener以添加自定義操作*/
public?class?IntervenRunListener?implements?SpringApplicationRunListener?{private?final?SpringApplication?application;private?final?String[]?args;public?IntervenRunListener(SpringApplication?application,?String[]?args)?{this.application?=?application;this.args?=?args;}@Overridepublic?void?starting()?{System.out.println("IntervenRunListener?starting");}@Overridepublic?void?environmentPrepared(ConfigurableEnvironment?environment)?{System.out.println("IntervenRunListener?environmentPrepared");}@Overridepublic?void?contextPrepared(ConfigurableApplicationContext?context)?{System.out.println("IntervenRunListener?contextPrepared");}@Overridepublic?void?contextLoaded(ConfigurableApplicationContext?context)?{System.out.println("IntervenRunListener?contextLoaded");}@Overridepublic?void?started(ConfigurableApplicationContext?context)?{System.out.println("IntervenRunListener?started");}@Overridepublic?void?running(ConfigurableApplicationContext?context)?{System.out.println("IntervenRunListener?running");}@Overridepublic?void?failed(ConfigurableApplicationContext?context,?Throwable?exception)?{System.out.println("IntervenRunListener?failed");}
}
在上述代碼中,我們新建了一個名為IntervenRunListener
的自定義SpringApplicationRunListener
,并在starting()
、environmentPrepared()
、contextPrepared()
、contextLoaded()
、started()
、running()
和failed()
方法中添加了自定義操作。
接下來,我們需要告訴Spring Boot使用這個自定義的SpringApplicationRunListener
,上述代碼中的IntervenRunListener
需要被注冊才能生效。可以通過在src/main/resources/META-INF/spring.factories
文件中指定注冊項的方式來注冊:
org.springframework.boot.SpringApplicationRunListener=
org.zyf.javabasic.springextend.runext.IntervenRunListener
(三)ApplicationRunner擴展
ApplicationRunner
是Spring Boot提供的一種擴展點,它允許在Spring Boot應用程序啟動時執行一些預配置操作。這些操作可以包括預熱緩存,初始化數據庫連接等。以下是一些用途:
-
數據庫初始化:?
ApplicationRunner
可以用于執行數據庫初始化操作。例如,我們可以在應用程序啟動時創建數據庫表格,插入初始數據等操作。這對于確保數據庫的正確性和可用性非常有用,以及為整個應用程序提供更好的可維護性。 -
緩存預熱:?緩存在應用程序中非常重要,它可以大大提高應用程序的性能。但是,由于緩存通常是“懶加載”的,所以在應用程序第一次使用它們時,需要花費一些時間來加載它們。使用
ApplicationRunner
,我們可以在應用程序啟動后立即加載緩存,而不是等到應用程序第一次使用它們時加載。這可以大大減少應用程序響應時間,并提高用戶體驗。 -
環境檢查:?為了確保應用程序能夠正常運行,我們需要檢查它所在的環境是否滿足應用程序的要求。例如,我們可能需要檢查數據庫是否可用,檢查文件系統是否可寫等。使用
ApplicationRunner
,我們可以在應用程序啟動時立即執行這些檢查,并在應用程序無法正常運行時采取適當的措施,如打印警告或拋出異常。
總之,ApplicationRunner
可以用于執行任何需要在應用程序啟動時進行的操作。它為應用程序提供了一種簡單的擴展點,可以使我們輕松地實現預配置和初始化操作。
以下從緩存預熱和環境檢查給出簡單的代碼示例。
緩存預熱
在應用程序啟動后立即加載緩存,可以避免在應用程序第一次使用緩存時的延遲。以下是一個簡單的示例,演示如何使用ApplicationRunner
在應用程序啟動時加載緩存:
package?org.zyf.javabasic.springextend.runext;import?org.springframework.boot.ApplicationArguments;
import?org.springframework.boot.ApplicationRunner;
import?org.springframework.stereotype.Component;/***?@author?woniu*?@description?演示如何使用ApplicationRunner在應用程序啟動時加載緩存*/
@Component
public?class?CacheInitiator?implements?ApplicationRunner?{@Overridepublic?void?run(ApplicationArguments?args)?throws?Exception?{System.out.println("CacheInitiator?cache?deal!");}
}
在應用程序啟動時,ApplicationRunner
接口的run方法將被自動調用,從而將一些初始數據加載到緩存中。當應用程序需要訪問緩存時,它們可以立即從緩存中獲取數據,而不必等待它們被“懶加載”的時間。這將大大提高應用程序的性能和用戶體驗。
環境檢查
以下是一個簡單的示例,演示如何使用ApplicationRunner
在應用程序啟動時執行環境檢查:
package?org.zyf.javabasic.springextend.runext;import?org.springframework.boot.ApplicationArguments;
import?org.springframework.boot.ApplicationRunner;
import?org.springframework.stereotype.Component;/***?@author?woniu*?@description?演示如何使用ApplicationRunner在應用程序啟動時執行環境檢查*/
@Component
public?class?EnvironmentChecker?implements?ApplicationRunner?{@Overridepublic?void?run(ApplicationArguments?args)?throws?Exception?{//?檢查數據庫是否可用System.out.println("EnvironmentChecker?DatabaseConnection?checkConnection!?");//?檢查文件系統是否可寫System.out.println("EnvironmentChecker?FileStorage?checkWriteAccess!?");}
}
在應用程序啟動時,ApplicationRunner
接口的run方法將被自動調用,從而執行環境檢查操作。當應用程序無法正常運行時,它們將拋出一個運行時異常,包含適當的錯誤消息,以幫助我們進行故障排除和修復操作。
(四)CommandLineRunner擴展
CommandLineRunner
接口用于在應用程序啟動時執行一些命令行操作。這在調試應用程序、自動化部署、初始化系統配置等方面非常有用。
在較復雜的業務場景下,我們可以使用CommandLineRunner
接口來擴展應用程序。
首先,我們可以將一些常用的業務邏輯封裝在命令行工具中,然后在應用程序啟動時通過執行這些命令來進行操作。例如,我們可以創建一個名為UserImportCommand
的命令行工具,用于導入用戶數據到應用程序中。在應用程序啟動時,可以執行UserImportCommand
來導入用戶數據。
其次,我們可以使用CommandLineRunner
接口來定制化應用程序的啟動過程。例如,我們可以創建一個名為StartupTasks
的類,并實現CommandLineRunner
接口。在run方法中,我們可以執行任何我們需要在應用程序啟動時完成的任務,如加載配置文件、初始化緩存等。
最后,我們可以結合使用ApplicationRunner
和CommandLineRunner
來完成更復雜的任務。例如,我們可以創建一個名為InitializationRunner
的類,實現ApplicationRunner
和CommandLineRunner
接口,并在其中執行所有初始化任務。這樣,在應用程序啟動時,不僅可以自動執行初始化任務,還可以通過命令行手動執行這些任務。
“綜上所述,
CommandLineRunner
接口在業務擴展方面有著廣闊的應用前景,在實際業務場景中,可以根據自己的需求進行靈活應用和擴展。
應用舉例一:UserImportCommand命令行工具
以下是一個簡單的示例,演示如何使用CommandLineRunner
接口創建一個命令行工具,用于導入用戶數據到應用程序中。
package?org.zyf.javabasic.springextend.runext;import?com.google.common.collect.Lists;
import?org.springframework.boot.CommandLineRunner;
import?org.springframework.stereotype.Component;
import?org.zyf.javabasic.common.User;import?java.util.List;/***?@author?woniu*?@description?演示如何使用CommandLineRunner接口創建一個名為UserImportCommand的命令行工具,用于導入用戶數據到應用程序中。*/
@Component
public?class?UserImportCommand?implements?CommandLineRunner?{@Overridepublic?void?run(String...?args)?throws?Exception?{List<User>?users?=?readUserFromFile("fileName");System.out.println("UserImportCommand?readUserFromFile?importUsers!");}//?從數據文件中讀取用戶信息private?List<User>?readUserFromFile(String?fileName)?{//?省略代碼,從文件中讀取用戶信息,返回一個User對象列表return?Lists.newArrayList();}
}
在應用程序啟動時,CommandLineRunner
接口的run方法將被自動調用,并將命令行參數作為字符串數組傳遞給run方法。
上面展示的時候并沒有使用入參,當需要導入用戶數據時,可以執行如下命令:
java?-jar?myapp.jar?user-import?users.txt
其中,myapp.jar是應用程序運行的jar包,user-import
是命令行工具的名稱,users.txt是要導入的用戶數據文件名。
應用舉例二:定制化應用程序的啟動過程
可以使用CommandLineRunner
接口來定制化應用程序的啟動過程。下面是一個示例,演示如何使用CommandLineRunner
來執行一些自定義啟動任務:
package?org.zyf.javabasic.springextend.runext;import?org.springframework.boot.CommandLineRunner;
import?org.springframework.stereotype.Component;/***?@author?woniu*?@description?演示如何使用CommandLineRunner來執行一些自定義啟動任務*/
@Component
public?class?StartupTasks?implements?CommandLineRunner?{@Overridepublic?void?run(String...?args)?throws?Exception?{//?加載應用程序配置System.out.println("StartupTasks?configService?loadConfig");//?初始化緩存System.out.println("StartupTasks?cacheService?initialize");}
}
在應用程序啟動時,CommandLineRunner
接口的run方法將被自動調用,并且我們的自定義啟動任務將會被執行。通過使用CommandLineRunner
接口,我們可以執行任何自定義的啟動任務,以滿足特定的應用程序需求。
(五)所有擴展驗證
驗證以上配置是否生效很簡單,只需要啟動程序查看打印效果即可,以下給出一些基本的展示效果:
二、加快SpringBoot項目啟動
公司級大多數SpringBoot 項目在日常開發過程中發現服務啟動過程異常緩慢,常常需要4-7分鐘才能暴露端口,有的時候甚至在十分鐘左右,嚴重降低開發效率。
若要優化 Spring Boot 程序的啟動時間以縮短啟動時間,可以考慮以下幾個方面的優化措施:
-
減少依賴項:?評估項目的依賴項,并確保只引入必要的依賴。較多的依賴項可能會增加啟動時間,因為它們需要被掃描和初始化。通過刪除不需要的依賴項或僅引入必要的模塊,可以減少類路徑的掃描和初始化時間。
-
調整自動配置:?Spring Boot 的自動配置是一個強大的特性,但有時可能會引入不必要的組件和功能。通過調整自動配置,可以精確地指定所需的配置,避免加載不必要的組件,從而減少啟動時間。
-
啟用懶加載:?將一些不常用的組件設置為懶加載,即在需要時才進行初始化。通過懶加載,可以避免在啟動階段初始化不必要的組件,從而加快啟動時間。可以使用 Spring Framework 的?
@Lazy
?注解或在配置類中進行相應的配置。 -
啟用編譯時優化:?使用 Spring Boot 2.4 及更高版本,你可以通過啟用編譯時優化來加快啟動時間。通過在 pom.xml 文件中設置?
<compilerArgs>
?屬性,使用?--add-opens
?選項來啟用編譯時優化。這可以減少反射操作的開銷,從而提高啟動性能。 -
調整日志級別:?Spring Boot 默認啟用了相對較高的日志級別,這可能會導致大量的日志輸出,從而增加啟動時間。通過將日志級別調整為更低的級別,如將 INFO 調整為 WARN,可以減少日志輸出,從而縮短啟動時間。
-
使用緩存:?Spring Boot 在啟動過程中會進行多個步驟的掃描和初始化。通過使用緩存機制,可以緩存一些元數據和初始化結果,避免重復的掃描和初始化操作,從而提高啟動性能。可以使用 Spring Boot 的緩存機制或其他緩存庫來實現。
這些是一些常見的優化措施,可以幫助縮短 Spring Boot 程序的啟動時間。然而,優化的效果取決于具體的應用程序和場景,因此建議根據實際情況進行評估和測試。
(一)減少依賴項以縮短啟動時間
減少依賴項具體的分析和說明
-
評估依賴項:?首先,需要仔細評估項目的依賴項。查看項目的 pom.xml(如果使用Maven)或 build.gradle(如果使用Gradle)文件,以了解所有引入的依賴項。檢查每個依賴項的用途和必要性。
-
刪除不需要的依賴項:?確定哪些依賴項是不需要的或沒有被項目使用的。這些無用的依賴項可能會增加類路徑的掃描和初始化時間,從而拖慢啟動過程。可以通過移除或注釋掉不需要的依賴項來減少不必要的加載和初始化。
-
僅引入必要的模塊:?對于一些大型的依賴項,例如Spring Boot的模塊,可以根據項目的需求僅引入必要的模塊。Spring Boot提供了模塊化的方式,允許你選擇性地引入只需要的模塊。通過僅引入必要的模塊,可以減少初始化過程中的掃描和加載時間。
-
排除不必要的傳遞依賴項:?一些依賴項會引入其他的傳遞依賴項。如果這些傳遞依賴項不是項目所需的,可以通過在依賴項的配置中排除它們來減少類路徑的掃描和初始化。這可以通過在項目的構建文件中配置
<exclusions>
標簽來實現。 -
使用更輕量級的替代方案:?有時,某個依賴項可能有較重的啟動開銷。在評估依賴項時,可以考慮使用更輕量級的替代方案,以減少啟動時間。例如,對于某個功能或工具庫,可能有多個不同的實現可供選擇,可以選擇具有較輕量級的實現。
總的來說,通過評估和優化項目的依賴項,可以減少不必要的加載和初始化過程,從而減少啟動時間。這需要仔細分析每個依賴項的用途,并確保只引入必要的依賴項和模塊。同時,需要保持項目的功能完整性和正確性,確保刪除的依賴項不會影響項目的正常運行。
減少依賴項案例分析
當涉及到減少依賴項以縮短啟動時間的案例分析,我們以一個簡單的Web應用為例,假設我們有一個基于Spring Boot的Web應用,該應用使用了以下依賴項:
-
spring-boot-starter-web
:用于構建Web應用程序的基本依賴項。 -
spring-boot-starter-data-jpa
:用于與數據庫進行交互的依賴項。 -
spring-boot-starter-security
:用于添加安全性功能的依賴項。 -
spring-boot-starter-test
:用于測試的依賴項。
在評估這些依賴項后,我們注意到以下情況:
-
項目中并沒有使用與數據庫交互的功能,因此?
spring-boot-starter-data-jpa
?可能是不必要的依賴項。 -
在項目中并沒有實現任何安全性功能,因此?
spring-boot-starter-security
?也可能是不必要的依賴項。
基于以上分析,我們可以采取以下措施來優化啟動時間:
-
刪除不需要的依賴項:?從項目的構建文件(如pom.xml)中刪除不需要的依賴項,即?
spring-boot-starter-data-jpa
?和?spring-boot-starter-security
。 -
清理類路徑掃描和初始化:?由于刪除了不必要的依賴項,應用程序在啟動時不再需要掃描和初始化與數據庫和安全性相關的組件,從而減少啟動時間。
-
進行相關測試:?在進行以上更改后,確保對應用程序進行全面的測試,以確保沒有因刪除依賴項而引起的不可預料的問題。
通過這樣的優化措施,我們可以減少應用程序的啟動時間,特別是在大型項目中,當引入了大量不必要的依賴項時,效果會更為顯著。然而,需要注意,每個項目都有其特定的依賴項和功能需求,因此優化策略可能會有所不同。
(二)調整自動配置以縮短啟動時間
調整自動配置具體分析說明
-
了解自動配置機制:?首先,了解 Spring Boot 的自動配置機制是很重要的。Spring Boot 使用條件化配置來根據項目的依賴和配置來自動決定哪些組件應該被加載和配置。條件注解(如?
@ConditionalOnClass
、@ConditionalOnProperty
?等)用于根據特定的條件來決定組件是否應該被自動配置。 -
檢查自動配置類:?查看自動配置類,了解每個自動配置類所做的配置和加載的組件。可以在 Spring Boot 的官方文檔或源代碼中找到自動配置類的詳細信息。對于不必要的組件,可以嘗試找到對應的自動配置類并進行分析。
-
排除不必要的自動配置:?通過使用?
@EnableAutoConfiguration
?注解的 exclude 屬性,可以排除不需要的自動配置類。這可以在主應用程序類上進行配置。通過排除不必要的自動配置類,可以避免加載不需要的組件和功能,從而減少啟動時間。 -
自定義自動配置:?如果發現某個自動配置類加載了不必要的組件,但又需要其他配置,可以自定義自動配置類。通過創建一個帶有?
@Configuration
?注解的配置類,并在其中指定所需的配置,可以覆蓋默認的自動配置。這樣可以精確地指定所需的配置,避免加載不必要的組件。 -
配置條件:?有些自動配置類提供了條件注解,可以使用這些條件注解來根據項目的需求進行配置。例如,使用?
@ConditionalOnProperty
?注解可以根據配置屬性的值來決定是否應用該自動配置。通過合理配置這些條件,可以避免加載不必要的組件。
通過調整自動配置,可以精確地指定所需的配置,避免加載不必要的組件和功能,從而減少啟動時間。需要注意的是,在調整自動配置時,確保對應用程序進行全面的測試,以確保所需的功能和組件仍然正常工作。
調整自動配置案例分析
假設我們有一個基于Spring Boot的Web應用,該應用使用了以下自動配置:
-
spring-boot-starter-web
:用于構建Web應用程序的基本自動配置。 -
spring-boot-starter-data-jpa
:用于與數據庫進行交互的自動配置。 -
spring-boot-starter-security
:用于添加安全性功能的自動配置。
在評估這些自動配置后,我們注意到以下情況:
-
項目中并沒有使用與數據庫交互的功能,因此?
spring-boot-starter-data-jpa
?可能是不必要的自動配置。 -
在項目中并沒有實現任何安全性功能,因此?
spring-boot-starter-security
?也可能是不必要的自動配置。
基于以上分析,我們可以采取以下措施來優化啟動時間:
排除不必要的自動配置:在主應用程序類上使用?@EnableAutoConfiguration
?注解的 exclude 屬性,排除?spring-boot-starter-data-jpa
?和?spring-boot-starter-security
?的自動配置。
@SpringBootApplication(exclude?=?{DataJpaAutoConfiguration.class,?SecurityAutoConfiguration.class})
public?class?MyApplication?{//?...
}
自定義自動配置:如果需要其他的配置,可以創建一個自定義的自動配置類,并在其中指定所需的配置。例如,對于與數據庫交互的功能,可以創建一個自定義的配置類,僅包含必要的配置項。
@Configuration
public?class?CustomDataJpaAutoConfiguration?{//?...
}
通過以上優化措施,我們排除了不必要的自動配置,并自定義了所需的配置,避免加載不必要的組件和功能,從而減少啟動時間。這種方式可以根據項目的實際需求靈活調整自動配置,以提高啟動性能。然而,需要注意,在進行以上更改后,確保對應用程序進行全面的測試,以確保所需的功能和組件仍然正常工作。
(三)啟用懶加載以縮短啟動時間
啟用懶加載具體分析說明
啟用懶加載是一種有效的方法來減少啟動時間,只有在需要時才初始化不常用的組件。以下是具體分析說明:
-
確定需要懶加載的組件:?仔細評估項目中的組件,并確定哪些組件是不常用的,可以延遲加載。這些組件可能包括大型的第三方庫、復雜的初始化過程或與特定功能相關的組件。
-
使用 @Lazy 注解:?在需要懶加載的組件上使用 Spring Framework 的?
@Lazy
?注解。將?@Lazy
?注解應用于組件的聲明處,以指示該組件應該在需要時才進行初始化。例如:
@Component
@Lazy
public?class?MyLazyComponent?{//?...
}
-
在配置類中進行配置:?如果你使用的是配置類來進行組件的配置,你可以在配置類的方法上使用 @Lazy 注解,將需要懶加載的組件進行標記。例如:
@Configuration
public?class?MyConfig?{@Bean@Lazypublic?MyLazyComponent?myLazyComponent()?{return?new?MyLazyComponent();}
}
-
重新構建和運行應用程序:?保存更改后,重新構建并運行應用程序。在啟動過程中,被標記為懶加載的組件將不會立即初始化,只有在首次訪問時才會進行初始化。這樣可以避免啟動階段初始化不必要的組件,從而加快啟動時間。
通過啟用懶加載,可以延遲初始化不常用的組件,減少啟動時間。這在項目中特別適用于那些具有復雜初始化過程或與特定功能相關的組件。需要注意的是,懶加載的組件在第一次訪問時可能會引入額外的延遲,因此在評估和標記組件時要權衡性能和實際需求。
總結起來,通過使用 Spring Framework 的?@Lazy
?注解或在配置類中進行相應的配置,可以啟用懶加載,從而在需要時才初始化不常用的組件,加快應用程序的啟動時間。
啟用懶加載案例分析
假設我們有一個基于 Spring Boot 的電子商務應用程序,其中包含一些復雜的服務和組件。我們注意到啟動時間較長,并且發現其中一個原因是某些組件的初始化過程相對較慢。
在進一步分析后,我們確定以下組件是不常用的,并且可以通過懶加載來延遲初始化:
-
PaymentService
:用于處理支付的服務組件。 -
SearchService
:用于執行商品搜索的服務組件。
這兩個組件在啟動時不是必需的,因為它們只在用戶執行特定操作時才會被使用。
我們可以使用 Spring Framework 的?@Lazy
?注解來標記這些組件,將它們設置為懶加載。
@Service
@Lazy
public?class?PaymentService?{//?...
}@Service
@Lazy
public?class?SearchService?{//?...
}
通過在組件的聲明處添加 @Lazy 注解告訴 Spring 框架在需要使用這些組件時才進行初始化。
重新構建并運行應用程序后,啟動階段將不會立即初始化?PaymentService
?和?SearchService
?組件。只有當用戶執行相關操作時,才會觸發它們的初始化。這樣可以減少啟動時間,并且在應用程序啟動后,只有真正需要時才會占用資源。
“需要注意的是,在標記組件為懶加載時,確保仔細評估其對應用程序功能的影響。確保懶加載的組件在實際使用時能夠正確地被初始化,并且不會導致功能上的問題。
(四)啟用編譯時優化以縮短啟動時間
啟用編譯時優化是一種有效的方法來加快 Spring Boot 應用程序的啟動時間,特別是在使用 Spring Boot 2.4 及更高版本時。以下是具體的分析和說明:
1.確認使用的 Spring Boot 版本:?確保你的項目使用的是 Spring Boot 2.4 或更高版本。編譯時優化功能是在 Spring Boot 2.4 中引入的。
2.配置 pom.xml 文件:?在項目的 pom.xml 文件中,找到?<build>
?元素,并在其中的?<plugins>
?元素下添加 Maven Compiler 插件配置。在 Maven Compiler 插件配置中,使用?<compilerArgs>
?屬性來設置編譯器選項。
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><compilerArgs><arg>--add-opens</arg><arg>java.base/java.lang=ALL-UNNAMED</arg><arg>--add-opens</arg><arg>java.base/java.util=ALL-UNNAMED</arg><!--?添加其他需要的?--add-opens?選項?--></compilerArgs></configuration></plugin></plugins>
</build>
在?<compilerArgs>
?屬性中,我們使用?--add-opens
?選項來指定需要開放的包和模塊。上述示例中,我們設置了兩個?--add-opens
?選項,分別是?java.lang
?和?java.util
?包。你還可以根據需要添加其他的?--add-opens
?選項,以開放其他需要的包和模塊。
3.重新構建應用程序:?保存更改后,重新構建應用程序。在編譯過程中,編譯器將使用指定的編譯器選項,啟用編譯時優化。
啟用編譯時優化可以減少反射操作的開銷,從而提高應用程序的啟動性能。它通過使用?--add-opens
?選項來開放特定的包和模塊,使得一些反射操作可以直接訪問,而無需通過反射 API。
“需要注意的是,編譯時優化可能會因為項目的具體情況而有所不同。在應用該優化時,需要進行測試和評估,確保應用程序在啟用編譯時優化后仍然能夠正常運行。
總結起來,通過在 pom.xml 文件中配置 Maven Compiler 插件,使用?<compilerArgs>
?屬性設置?--add-opens
?選項,可以啟用編譯時優化來加快 Spring Boot 應用程序的啟動時間。根據項目的需求,你可以添加其他需要的?--add-opens
?選項,以滿足特定的優化需求。
(五)調整日志級別以縮短啟動時間
調整日志級別是一種簡單而有效的方法來減少啟動時間,特別是當應用程序的日志輸出量較大時。以下是具體的分析和說明:
1.確定適當的日志級別:?仔細評估你的應用程序,并確定適當的日志級別。通常,將日志級別從較高的級別(如 DEBUG 或 INFO)調整為較低的級別(如 WARN 或 ERROR)是一種常見的優化策略。較低的日志級別會減少輸出的日志消息數量。
2.配置日志級別:?在 Spring Boot 應用程序的配置文件(如 application.properties 或 application.yml)中,找到與日志相關的配置項。根據你使用的日志框架(如 Logback、Log4j2 或 JUL),進行相應的配置。例如,對于 Logback,你可以在 application.properties 文件中添加以下配置:
logging.level.root=WARN
或者在 application.yml 文件中添加以下配置:
logging:level:root:?WARN
這將將根日志記錄器的級別設置為 WARN,從而只輸出 WARN 級別及以上的日志消息。
3.重新構建和運行應用程序:?保存更改后,重新構建并運行應用程序。在啟動過程中,日志框架將根據配置的日志級別來決定是否輸出特定級別的日志消息。通過將日志級別調整為較低的級別,可以減少輸出的日志消息數量,從而加快啟動時間。
“需要注意的是,調整日志級別可能會導致在應用程序運行時缺少某些重要的日志信息。因此,在進行日志級別調整時,應權衡性能和需要的日志信息,并確保不會影響應用程序的正常運行和故障排查。
總結起來,通過將日志級別調整為較低的級別,如將 INFO 調整為 WARN,可以減少日志輸出量,從而縮短應用程序的啟動時間。在調整日志級別時,需要確保仍能獲取到足夠的日志信息以滿足應用程序的需求。
(六)使用緩存以縮短啟動時間
使用緩存是一種有效的方法來提高 Spring Boot 應用程序的啟動性能。通過緩存一些元數據和初始化結果,可以避免重復的掃描和初始化操作,從而減少啟動時間。以下是具體的分析和說明:
1.使用 Spring Boot 的緩存機制:?Spring Boot 提供了內置的緩存機制,可以通過使用?@EnableCaching
?注解來啟用緩存功能。在需要緩存的組件或方法上添加?@Cacheable
?注解,以指示該組件或方法的結果應該被緩存。
@EnableCaching
@SpringBootApplication
public?class?MyApplication?{//?...
}@Service
public?class?MyService?{@Cacheable("myCache")public?MyData?getData(String?key)?{//?從數據庫或其他地方獲取數據//?...}
}
在上述示例中,我們通過在 MyService 的?getData()
?方法上添加?@Cacheable("myCache")
?注解,指定該方法的結果應該被緩存,并使用名為 "myCache" 的緩存區域。通過緩存結果,當多次調用?getData()
?方法時,如果相同的參數值被傳遞進來,將會直接從緩存中獲取結果,而不需要重復的數據獲取操作。
2.使用其他緩存庫:?除了使用 Spring Boot 的緩存機制外,你還可以選擇使用其他的緩存庫,如 Ehcache、Redis 或 Caffeine。這些緩存庫提供了更高級的緩存功能和配置選項,可以滿足更復雜的需求。例如,使用 Ehcache 作為緩存庫,你可以在應用程序的配置文件中配置 Ehcache 緩存:
<dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId>
</dependency>
然后,在需要緩存的方法上使用 Ehcache 注解,如?@org.ehcache.Cacheable
。使用其他緩存庫時,需要根據庫的文檔和配置方式來進行相應的設置和使用。
無論是使用 Spring Boot 的緩存機制還是其他緩存庫,通過緩存一些元數據和初始化結果,可以避免重復的掃描和初始化操作,從而減少啟動時間。但需要注意的是,在使用緩存時,要確保緩存的數據和結果的一致性,并考慮緩存的過期策略和清理機制,以避免緩存數據過時或占用過多內存。
總結起來,使用緩存是一種優化啟動時間的有效方法。可以使用 Spring Boot 的緩存機制或其他緩存庫來實現緩存功能,并根據具體需求和庫的使用方式進行配置和使用。通過緩存一些元數據和初始化結果,可以避免重復操作,提高應用程序的啟動性能。
最后說一句(求關注!別白嫖!)
如果這篇文章對您有所幫助,或者有所啟發的話,求一鍵三連:點贊、轉發、在看。
關注公眾號:woniuxgg,在公眾號中回復:筆記??就可以獲得蝸牛為你精心準備的java實戰語雀筆記,回復面試、開發手冊、有超贊的粉絲福利!