您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何掌握Spring”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何掌握Spring”吧!
Spring 是一個控制反轉依賴管理的容器,作為 Java Web 的開發人員,基本沒有不熟悉 Spring 技術棧的,盡管在依賴注入領域,Java Web 領域不乏其他優秀的框架,如 google 開源的依賴管理框架 guice,如 Jersey web 框架等。但 Spring 已經是 Java Web 領域使用最多,應用最廣泛的 Java 框架。
此文將專注講解如何在 Spring 容器啟動時實現我們自己想要實現的邏輯。我們時常會遇到在 Spring 啟動的時候必須完成一些初始化的操作,如創建定時任務,創建連接池等。
如果沒有 Spring 容器,不依賴于 Spring 的實現,回歸 Java 類實現本身,我們可以在靜態代碼塊,在類構造函數中實現相應的邏輯,Java 類的初始化順序依次是靜態變量 > 靜態代碼塊 > 全局變量 > 初始化代碼塊 > 構造器。
比如,Log4j 的初始化,就是在 LogManager 的靜態代碼塊中實現的:
static { Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG)); repositorySelector = new DefaultRepositorySelector(h); String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null); if(override == null || "false".equalsIgnoreCase(override)) { String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY, null); String configuratorClassName = OptionConverter.getSystemProperty(CONFIGURATOR_CLASS_KEY, null); URL url = null; if(configurationOptionStr == null) { url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE); if(url == null) { url = Loader.getResource(DEFAULT_CONFIGURATION_FILE); } } else { try { url = new URL(configurationOptionStr); } catch (MalformedURLException ex) { url = Loader.getResource(configurationOptionStr); } } if(url != null) { LogLog.debug("Using URL ["+url+"] for automatic log4j configuration."); try { OptionConverter.selectAndConfigure(url, configuratorClassName,LogManager.getLoggerRepository()); } catch (NoClassDefFoundError e) { LogLog.warn("Error during default initialization", e); } } else { LogLog.debug("Could not find resource: ["+configurationOptionStr+"]."); } } else { LogLog.debug("Default initialization of overridden by " + DEFAULT_INIT_OVERRIDE_KEY + "property."); } }
比如在構造函數中實現相應的邏輯:
@Component public class CustomBean { @Autowired private Environment env; public CustomBean() { env.getActiveProfiles(); } }
這里考驗一下各位,上面的代碼是否可以正常運行。—— 不行,構造函數中的env將會發生NullPointException異常。這是因為在 Spring 中將先初始化 Bean,也就是會先調用類的構造函數,然后才注入成員變量依賴的 Bean(@Autowired和@Resource注解修飾的成員變量),注意@Value等注解的配置的注入也是在構造函數之后。
PostConstruct
在 Spring 中,我們可以使用@PostConstruct在 Bean 初始化之后實現相應的初始化邏輯,@PostConstruct修飾的方法將在 Bean 初始化完成之后執行,此時 Bean 的依賴也已經注入完成,因此可以在方法中調用注入的依賴 Bean。
@Component public class CustomBean { @Autowired private Environment env; @PostConstruce public void init() { env.getActiveProfiles(); } }
與@PostConstruct相對應的,如果想在 Bean 注銷時完成一些清掃工作,如關閉線程池等,可以使用@PreDestroy注解:
@Component public class CustomBean { @Autowired private ExecutorService executor = Executors.newFixedThreadPool(1) @PreDestroy public void destroy() { env.getActiveProfiles(); } }
InitializingBean
實現 Spring 的InitializingBean接口同樣可以實現以上在 Bean 初始化完成之后執行相應邏輯的功能,實現InitializingBean接口,在afterPropertiesSet方法中實現邏輯:
@Component public class CustomBean implements InitializingBean { private static final Logger LOG = Logger.getLogger(InitializingBeanExampleBean.class); @Autowired private Environment environment; @Override public void afterPropertiesSet() throws Exception { LOG.info(environment.getDefaultProfiles()); } }
ApplicationListener
我們可以在 Spring 容器初始化的時候實現我們想要的初始化邏輯。這時我們就可以使用到 Spring 的初始化事件。Spring 有一套完整的事件機制,在 Spring 啟動的時候,Spring 容器本身預設了很多事件,在 Spring 初始化的整個過程中在相應的節點觸發相應的事件,我們可以通過監聽這些事件來實現我們的初始化邏輯。Spring 的事件實現如下:
ApplicationEvent,事件對象,由 ApplicationContext 發布,不同的實現類代表不同的事件類型。
ApplicationListener,監聽對象,任何實現了此接口的 Bean 都會收到相應的事件通知。實現了 ApplicationListener 接口之后,需要實現方法 onApplicationEvent(),在容器將所有的 Bean 都初始化完成之后,就會執行該方法。
與 Spring Context 生命周期相關的幾個事件有以下幾個:
ApplicationStartingEvent: 這個事件在 Spring Boot 應用運行開始時,且進行任何處理之前發送(除了監聽器和初始化器注冊之外)。
ContextRefreshedEvent: ApplicationContext 被初始化或刷新時,該事件被發布。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發生。
ContextStartedEvent: 當使用 ConfigurableApplicationContext 接口中的 start() 方法啟動 ApplicationContext 時,該事件被觸發。你可以查詢你的數據庫,或者你可以在接受到這個事件后重啟任何停止的應用程序。
ApplicationReadyEvent: 這個事件在任何 application/ command-line runners 調用之后發送。
ContextClosedEvent: 當使用 ConfigurableApplicationContext 接口中的 close() 方法關閉 ApplicationContext 時,該事件被觸發。一個已關閉的上下文到達生命周期末端;它不能被刷新或重啟。
ContextStoppedEvent: Spring 最后完成的事件。
因此,如果我們想在 Spring 啟動的時候實現一些相應的邏輯,可以找到 Spring 啟動過程中符合我們需要的事件,通過監聽相應的事件來完成我們的邏輯:
@Component @Slf4j public class StartupApplicationListenerExample implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { log.info("Subject ContextRefreshedEvent"); } }
除了通過實現ApplicationListener接口來監聽相應的事件,Spring 的事件機制也實現了通過@EventListener注解來監聽相對應事件:
@Component @Slf4j public class StartupApplicationListenerExample { @EventListener public void onApplicationEvent(ContextRefreshedEvent event) { log.info("Subject ContextRefreshedEvent"); } }
Spring Event 是一套完善的進程內事件發布訂閱機制,我們除了用來監聽 Spring 內置的事件,也可以使用 Spring Event 實現自定義的事件發布訂閱功能。
Constructor 注入
在學習 Spring 的注入機制的時候,我們都知道 Spring 可以通過構造函數、Setter 和反射成員變量注入等方式。上面我們在成員變量上通過@Autoware注解注入依賴 Bean,但是在 Bean 的構造函數函數中卻無法使用到注入的 Bean(因為 Bean 還未注入),其實我們也是使用 Spring 的構造函數注入方式, 這也是 Spring 推薦的注入機制(在我們使用 IDEA 的時候,如果沒有關閉相應的代碼 Warning 機制,會發現在成員變量上的@Autoware是黃色的,也就是 idea 不建議的代碼)。Spring 更推薦構造函數注入的方式:
@Component @Slf4j public class ConstructorBean { private final Environment environment; @Autowired public LogicInConstructorExampleBean(Environment environment) { this.environment = environment; log.info(Arrays.asList(environment.getDefaultProfiles())); } }
CommandLineRunner
如果我們的項目使用的是 Spring Boot,那么可以使用 Spring Boot 提供的 CommandLineRunner 接口來實現初始化邏輯,Spring Boot 將在啟動初始化完成之后調用實現了CommandLineRunner的接口的run方法:
@Component @Slf4j public class CommandLineAppStartupRunner implements CommandLineRunner { @Override public void run(String...args) throws Exception { log.info("Increment counter"); } }
并且,多個CommandLineRunner實現,可以通過@Order來控制它們的執行順序。
SmartLifecycle
還有一種更高級的方法來實現我們的邏輯。這可以 Spring 高級開發必備技能哦。SmartLifecycle 不僅僅能在初始化后執行一個邏輯,還能再關閉前執行一個邏輯,并且也可以控制多個 SmartLifecycle 的執行順序,就像這個類名表示的一樣,這是一個智能的生命周期管理接口。
start():bean 初始化完畢后,該方法會被執行。
stop():容器關閉后,spring 容器發現當前對象實現了 SmartLifecycle,就調用 stop(Runnable), 如果只是實現了 Lifecycle,就調用 stop()。
isRunning:當前狀態,用來判你的斷組件是否在運行。
getPhase:控制多個 SmartLifecycle 的回調順序的,返回值越小越靠前執行 start() 方法,越靠后執行 stop() 方法。
isAutoStartup():start 方法被執行前先看此方法返回值,返回 false 就不執行 start 方法了。
stop(Runnable):容器關閉后,spring 容器發現當前對象實現了 SmartLifecycle,就調用 stop(Runnable), 如果只是實現了 Lifecycle,就調用 stop()。
@Component public class SmartLifecycleExample implements SmartLifecycle { private boolean isRunning = false; @Override public void start() { System.out.println("start"); isRunning = true; } @Override public int getPhase() { // 默認為 0 return 0; } @Override public boolean isAutoStartup() { // 默認為 false return true; } @Override public boolean isRunning() { // 默認返回 false return isRunning; } @Override public void stop(Runnable callback) { System.out.println("stop(Runnable)"); callback.run(); isRunning = false; } @Override public void stop() { System.out.println("stop"); isRunning = false; } }
感謝各位的閱讀,以上就是“如何掌握Spring”的內容了,經過本文的學習后,相信大家對如何掌握Spring這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。