偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

了解這些,你就可以在Spring啟動時為所欲為了

開發(fā) 前端
Spring 是一個控制反轉(zhuǎn)依賴管理的容器,作為 Java Web 的開發(fā)人員,基本沒有不熟悉 Spring 技術(shù)棧的,盡管在依賴注入領(lǐng)域,Java Web 領(lǐng)域不乏其他優(yōu)秀的框架,如 google 開源的依賴管理框架 guice,如 Jersey web 框架等。

[[374930]]

Spring 是一個控制反轉(zhuǎn)依賴管理的容器,作為 Java Web 的開發(fā)人員,基本沒有不熟悉 Spring 技術(shù)棧的,盡管在依賴注入領(lǐng)域,Java Web 領(lǐng)域不乏其他優(yōu)秀的框架,如 google 開源的依賴管理框架 guice,如 Jersey web 框架等。但 Spring 已經(jīng)是 Java Web 領(lǐng)域使用最多,應(yīng)用最廣泛的 Java 框架。

此文將專注講解如何在 Spring 容器啟動時實現(xiàn)我們自己想要實現(xiàn)的邏輯。我們時常會遇到在 Spring 啟動的時候必須完成一些初始化的操作,如創(chuàng)建定時任務(wù),創(chuàng)建連接池等。

如果沒有 Spring 容器,不依賴于 Spring 的實現(xiàn),回歸 Java 類實現(xiàn)本身,我們可以在靜態(tài)代碼塊,在類構(gòu)造函數(shù)中實現(xiàn)相應(yīng)的邏輯,Java 類的初始化順序依次是靜態(tài)變量 > 靜態(tài)代碼塊 > 全局變量 > 初始化代碼塊 > 構(gòu)造器。

比如,Log4j 的初始化,就是在 LogManager 的靜態(tài)代碼塊中實現(xiàn)的:

  1. static { 
  2.     Hierarchy h = new Hierarchy(new RootLogger((LevelLevel.DEBUG)); 
  3.     repositorySelector = new DefaultRepositorySelector(h); 
  4.  
  5.     String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null); 
  6.  
  7.     if(override == null || "false".equalsIgnoreCase(override)) { 
  8.           String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY, null); 
  9.           String configuratorClassName = OptionConverter.getSystemProperty(CONFIGURATOR_CLASS_KEY, null); 
  10.  
  11.           URL url = null
  12.  
  13.           if(configurationOptionStr == null) { 
  14.             url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE); 
  15.             if(url == null) { 
  16.               url = Loader.getResource(DEFAULT_CONFIGURATION_FILE); 
  17.             } 
  18.           } else { 
  19.             try { 
  20.               url = new URL(configurationOptionStr); 
  21.             } catch (MalformedURLException ex) { 
  22.               url = Loader.getResource(configurationOptionStr); 
  23.             } 
  24.           } 
  25.  
  26.           if(url != null) { 
  27.             LogLog.debug("Using URL ["+url+"] for automatic log4j configuration."); 
  28.             try { 
  29.                 OptionConverter.selectAndConfigure(url, configuratorClassName,LogManager.getLoggerRepository()); 
  30.             } catch (NoClassDefFoundError e) { 
  31.                 LogLog.warn("Error during default initialization", e); 
  32.             } 
  33.           } else { 
  34.               LogLog.debug("Could not find resource: ["+configurationOptionStr+"]."); 
  35.           } 
  36.     } else { 
  37.             LogLog.debug("Default initialization of overridden by " +  DEFAULT_INIT_OVERRIDE_KEY + "property."); 
  38.     } 

比如在構(gòu)造函數(shù)中實現(xiàn)相應(yīng)的邏輯:

  1. @Component 
  2. public class CustomBean { 
  3.  
  4.     @Autowired 
  5.     private Environment env; 
  6.  
  7.     public CustomBean() { 
  8.         env.getActiveProfiles(); 
  9.     } 

這里考驗一下各位,上面的代碼是否可以正常運(yùn)行。—— 不行,構(gòu)造函數(shù)中的env將會發(fā)生NullPointException異常。這是因為在 Spring 中將先初始化 Bean,也就是會先調(diào)用類的構(gòu)造函數(shù),然后才注入成員變量依賴的 Bean(@Autowired和@Resource注解修飾的成員變量),注意@Value等注解的配置的注入也是在構(gòu)造函數(shù)之后。

PostConstruct

在 Spring 中,我們可以使用@PostConstruct在 Bean 初始化之后實現(xiàn)相應(yīng)的初始化邏輯,@PostConstruct修飾的方法將在 Bean 初始化完成之后執(zhí)行,此時 Bean 的依賴也已經(jīng)注入完成,因此可以在方法中調(diào)用注入的依賴 Bean。

  1. @Component 
  2. public class CustomBean { 
  3.  
  4.     @Autowired 
  5.     private Environment env; 
  6.  
  7.     @PostConstruce 
  8.     public void init() { 
  9.         env.getActiveProfiles(); 
  10.     } 

與@PostConstruct相對應(yīng)的,如果想在 Bean 注銷時完成一些清掃工作,如關(guān)閉線程池等,可以使用@PreDestroy注解:

  1. @Component 
  2. public class CustomBean { 
  3.  
  4.     @Autowired 
  5.     private ExecutorService executor = Executors.newFixedThreadPool(1) 
  6.  
  7.     @PreDestroy 
  8.     public void destroy() { 
  9.         env.getActiveProfiles(); 
  10.     } 

InitializingBean

實現(xiàn) Spring 的InitializingBean接口同樣可以實現(xiàn)以上在 Bean 初始化完成之后執(zhí)行相應(yīng)邏輯的功能,實現(xiàn)InitializingBean接口,在afterPropertiesSet方法中實現(xiàn)邏輯:

  1. @Component 
  2. public class CustomBean implements InitializingBean { 
  3.  
  4.     private static final Logger LOG 
  5.       = Logger.getLogger(InitializingBeanExampleBean.class); 
  6.  
  7.     @Autowired 
  8.     private Environment environment; 
  9.  
  10.     @Override 
  11.     public void afterPropertiesSet() throws Exception { 
  12.         LOG.info(environment.getDefaultProfiles()); 
  13.     } 

ApplicationListener

我們可以在 Spring 容器初始化的時候?qū)崿F(xiàn)我們想要的初始化邏輯。這時我們就可以使用到 Spring 的初始化事件。Spring 有一套完整的事件機(jī)制,在 Spring 啟動的時候,Spring 容器本身預(yù)設(shè)了很多事件,在 Spring 初始化的整個過程中在相應(yīng)的節(jié)點觸發(fā)相應(yīng)的事件,我們可以通過監(jiān)聽這些事件來實現(xiàn)我們的初始化邏輯。Spring 的事件實現(xiàn)如下:

  • ApplicationEvent,事件對象,由 ApplicationContext 發(fā)布,不同的實現(xiàn)類代表不同的事件類型。
  • ApplicationListener,監(jiān)聽對象,任何實現(xiàn)了此接口的 Bean 都會收到相應(yīng)的事件通知。實現(xiàn)了 ApplicationListener 接口之后,需要實現(xiàn)方法 onApplicationEvent(),在容器將所有的 Bean 都初始化完成之后,就會執(zhí)行該方法。

與 Spring Context 生命周期相關(guān)的幾個事件有以下幾個:

  • ApplicationStartingEvent: 這個事件在 Spring Boot 應(yīng)用運(yùn)行開始時,且進(jìn)行任何處理之前發(fā)送(除了監(jiān)聽器和初始化器注冊之外)。
  • ContextRefreshedEvent: ApplicationContext 被初始化或刷新時,該事件被發(fā)布。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發(fā)生。
  • ContextStartedEvent: 當(dāng)使用 ConfigurableApplicationContext 接口中的 start() 方法啟動 ApplicationContext 時,該事件被觸發(fā)。你可以查詢你的數(shù)據(jù)庫,或者你可以在接受到這個事件后重啟任何停止的應(yīng)用程序。
  • ApplicationReadyEvent: 這個事件在任何 application/ command-line runners 調(diào)用之后發(fā)送。
  • ContextClosedEvent: 當(dāng)使用 ConfigurableApplicationContext 接口中的 close() 方法關(guān)閉 ApplicationContext 時,該事件被觸發(fā)。一個已關(guān)閉的上下文到達(dá)生命周期末端;它不能被刷新或重啟。
  • ContextStoppedEvent: Spring 最后完成的事件。

因此,如果我們想在 Spring 啟動的時候?qū)崿F(xiàn)一些相應(yīng)的邏輯,可以找到 Spring 啟動過程中符合我們需要的事件,通過監(jiān)聽相應(yīng)的事件來完成我們的邏輯:

  1. @Component 
  2. @Slf4j 
  3. public class StartupApplicationListenerExample implements ApplicationListener<ContextRefreshedEvent> { 
  4.  
  5.     @Override 
  6.     public void onApplicationEvent(ContextRefreshedEvent event) { 
  7.         log.info("Subject ContextRefreshedEvent"); 
  8.     } 

除了通過實現(xiàn)ApplicationListener接口來監(jiān)聽相應(yīng)的事件,Spring 的事件機(jī)制也實現(xiàn)了通過@EventListener注解來監(jiān)聽相對應(yīng)事件:

  1. @Component 
  2. @Slf4j 
  3. public class StartupApplicationListenerExample { 
  4.  
  5.     @EventListener 
  6.     public void onApplicationEvent(ContextRefreshedEvent event) { 
  7.         log.info("Subject ContextRefreshedEvent"); 
  8.     } 

Spring Event 是一套完善的進(jìn)程內(nèi)事件發(fā)布訂閱機(jī)制,我們除了用來監(jiān)聽 Spring 內(nèi)置的事件,也可以使用 Spring Event 實現(xiàn)自定義的事件發(fā)布訂閱功能。

Constructor 注入

在學(xué)習(xí) Spring 的注入機(jī)制的時候,我們都知道 Spring 可以通過構(gòu)造函數(shù)、Setter 和反射成員變量注入等方式。上面我們在成員變量上通過@Autoware注解注入依賴 Bean,但是在 Bean 的構(gòu)造函數(shù)函數(shù)中卻無法使用到注入的 Bean(因為 Bean 還未注入),其實我們也是使用 Spring 的構(gòu)造函數(shù)注入方式, 這也是 Spring 推薦的注入機(jī)制(在我們使用 IDEA 的時候,如果沒有關(guān)閉相應(yīng)的代碼 Warning 機(jī)制,會發(fā)現(xiàn)在成員變量上的@Autoware是黃色的,也就是 idea 不建議的代碼)。Spring 更推薦構(gòu)造函數(shù)注入的方式:

  1. @Component 
  2. @Slf4j 
  3. public class ConstructorBean { 
  4.  
  5.     private final Environment environment; 
  6.  
  7.     @Autowired 
  8.     public LogicInConstructorExampleBean(Environment environment) { 
  9.         this.environment = environment; 
  10.         log.info(Arrays.asList(environment.getDefaultProfiles())); 
  11.     } 

CommandLineRunner

如果我們的項目使用的是 Spring Boot,那么可以使用 Spring Boot 提供的 CommandLineRunner 接口來實現(xiàn)初始化邏輯,Spring Boot 將在啟動初始化完成之后調(diào)用實現(xiàn)了CommandLineRunner的接口的run方法:

  1. @Component 
  2. @Slf4j 
  3. public class CommandLineAppStartupRunner implements CommandLineRunner { 
  4.  
  5.     @Override 
  6.     public void run(String...args) throws Exception { 
  7.         log.info("Increment counter"); 
  8.     } 

并且,多個CommandLineRunner實現(xiàn),可以通過@Order來控制它們的執(zhí)行順序。

SmartLifecycle

還有一種更高級的方法來實現(xiàn)我們的邏輯。這可以 Spring 高級開發(fā)必備技能哦。SmartLifecycle 不僅僅能在初始化后執(zhí)行一個邏輯,還能再關(guān)閉前執(zhí)行一個邏輯,并且也可以控制多個 SmartLifecycle 的執(zhí)行順序,就像這個類名表示的一樣,這是一個智能的生命周期管理接口。

  • start():bean 初始化完畢后,該方法會被執(zhí)行。
  • stop():容器關(guān)閉后,spring 容器發(fā)現(xiàn)當(dāng)前對象實現(xiàn)了 SmartLifecycle,就調(diào)用 stop(Runnable), 如果只是實現(xiàn)了 Lifecycle,就調(diào)用 stop()。
  • isRunning:當(dāng)前狀態(tài),用來判你的斷組件是否在運(yùn)行。
  • getPhase:控制多個 SmartLifecycle 的回調(diào)順序的,返回值越小越靠前執(zhí)行 start() 方法,越靠后執(zhí)行 stop() 方法。
  • isAutoStartup():start 方法被執(zhí)行前先看此方法返回值,返回 false 就不執(zhí)行 start 方法了。
  • stop(Runnable):容器關(guān)閉后,spring 容器發(fā)現(xiàn)當(dāng)前對象實現(xiàn)了 SmartLifecycle,就調(diào)用 stop(Runnable), 如果只是實現(xiàn)了 Lifecycle,就調(diào)用 stop()。
  1. @Component 
  2. public class SmartLifecycleExample implements SmartLifecycle { 
  3.  
  4.     private boolean isRunning = false
  5.  
  6.     @Override 
  7.     public void start() { 
  8.         System.out.println("start"); 
  9.         isRunning = true
  10.     } 
  11.  
  12.     @Override 
  13.     public int getPhase() { 
  14.         // 默認(rèn)為 0 
  15.         return 0; 
  16.     } 
  17.  
  18.     @Override 
  19.     public boolean isAutoStartup() { 
  20.         // 默認(rèn)為 false 
  21.         return true
  22.     } 
  23.  
  24.     @Override 
  25.     public boolean isRunning() { 
  26.         // 默認(rèn)返回 false 
  27.         return isRunning; 
  28.     } 
  29.  
  30.     @Override 
  31.     public void stop(Runnable callback) { 
  32.         System.out.println("stop(Runnable)"); 
  33.         callback.run(); 
  34.         isRunning = false
  35.     } 
  36.  
  37.     @Override 
  38.     public void stop() { 
  39.         System.out.println("stop"); 
  40.  
  41.         isRunning = false
  42.     } 
  43.  

本文轉(zhuǎn)載自微信公眾號「碼哥字節(jié)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼哥字節(jié)公眾號。  

 

責(zé)任編輯:武曉燕 來源: 碼哥字節(jié)
相關(guān)推薦

2018-03-01 15:00:15

Oracle數(shù)據(jù)中心云計算

2017-02-13 09:33:32

2020-07-06 10:55:38

CIO首席信息官IT

2014-06-19 14:49:37

iCloud認(rèn)證令牌密碼

2022-10-17 07:16:08

SQL機(jī)器學(xué)習(xí)AI

2018-07-19 06:07:22

物聯(lián)網(wǎng)安全物聯(lián)網(wǎng)IOT

2022-01-29 08:34:54

OTN網(wǎng)絡(luò)架構(gòu)網(wǎng)絡(luò)

2019-04-22 12:25:40

UbuntuLinux IP地址

2021-02-23 12:30:21

VS CodeGithub代碼

2021-08-27 23:13:03

Windows 11Windows微軟

2022-02-28 22:58:04

云遷移IT開發(fā)

2022-02-28 17:57:44

云遷移云計算

2018-11-27 09:21:41

負(fù)載均衡機(jī)器Session

2020-11-19 08:00:03

打工人離職工作

2015-07-10 11:18:19

2018-12-03 08:04:25

負(fù)載均衡機(jī)器流量

2020-09-17 15:59:37

Java技術(shù)開發(fā)

2009-03-17 08:46:57

Windows 7微軟發(fā)布

2009-10-21 09:46:13

VB使用ArrayLi

2021-02-23 07:01:24

js小游戲技術(shù)
點贊
收藏

51CTO技術(shù)棧公眾號