<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          六種方式,教你在SpringBoot初始化時(shí)搞點(diǎn)事情!

          共 7356字,需瀏覽 15分鐘

           ·

          2021-09-02 22:36

          前言

          在實(shí)際工作中總是需要在項(xiàng)目啟動(dòng)時(shí)做一些初始化的操作,比如初始化線程池、提前加載好加密證書.......

          那么經(jīng)典問(wèn)題來(lái)了,這也是面試官經(jīng)常會(huì)問(wèn)到的一個(gè)問(wèn)題:有哪些手段在Spring Boot 項(xiàng)目啟動(dòng)的時(shí)候做一些事情?

          方法有很多種,下面介紹幾種常見(jiàn)的方法。

          1、監(jiān)聽(tīng)容器刷新完成擴(kuò)展點(diǎn)ApplicationListener<ContextRefreshedEvent>

          ApplicationContext事件機(jī)制是觀察者設(shè)計(jì)模式實(shí)現(xiàn)的,通過(guò)ApplicationEvent和ApplicationListener這兩個(gè)接口實(shí)現(xiàn)ApplicationContext的事件機(jī)制。

          Spring中一些內(nèi)置的事件如下:

          1. ContextRefreshedEvent:ApplicationContext 被初始化或刷新時(shí),該事件被發(fā)布。這也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法來(lái)發(fā)生。此處的初始化是指:所有的Bean被成功裝載,后處理Bean被檢測(cè)并激活,所有Singleton Bean 被預(yù)實(shí)例化,ApplicationContext容器已就緒可用。
          2. ContextStartedEvent:當(dāng)使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法啟動(dòng) ApplicationContext 時(shí),該事件被發(fā)布。你可以調(diào)查你的數(shù)據(jù)庫(kù),或者你可以在接受到這個(gè)事件后重啟任何停止的應(yīng)用程序。
          3. ContextStoppedEvent:當(dāng)使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 時(shí),發(fā)布這個(gè)事件。你可以在接受到這個(gè)事件后做必要的清理的工作。
          4. ContextClosedEvent:當(dāng)使用 ConfigurableApplicationContext 接口中的 close() 方法關(guān)閉 ApplicationContext 時(shí),該事件被發(fā)布。一個(gè)已關(guān)閉的上下文到達(dá)生命周期末端;它不能被刷新或重啟。
          5. RequestHandledEvent:這是一個(gè) web-specific 事件,告訴所有 bean HTTP 請(qǐng)求已經(jīng)被服務(wù)。只能應(yīng)用于使用DispatcherServlet的Web應(yīng)用。在使用Spring作為前端的MVC控制器時(shí),當(dāng)Spring處理用戶請(qǐng)求結(jié)束后,系統(tǒng)會(huì)自動(dòng)觸發(fā)該事件。

          好了,了解上面這些內(nèi)置事件后,我們可以監(jiān)聽(tīng)ContextRefreshedEvent在Spring Boot 啟動(dòng)時(shí)完成一些操作,代碼如下:

          @Component
          public class TestApplicationListener implements ApplicationListener<ContextRefreshedEvent>{
              @Override
              public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
                  System.out.println(contextRefreshedEvent);
                  System.out.println("TestApplicationListener............................");
              }
          }

          高級(jí)玩法

          可以自定事件完成一些特定的需求,比如:郵件發(fā)送成功之后,做一些業(yè)務(wù)處理。

          1. 自定義EmailEvent,代碼如下:
          public class EmailEvent extends ApplicationEvent{
             private String address;
             private String text;
             public EmailEvent(Object source, String address, String text){
             super(source);
                this.address = address;
                this.text = text;
             }
             public EmailEvent(Object source) {
               super(source);
             }
             //......address和text的setter、getter
          }
          1. 自定義監(jiān)聽(tīng)器,代碼如下:
          public class EmailNotifier implements ApplicationListener{
             public void onApplicationEvent(ApplicationEvent event) {
               if (event instanceof EmailEvent) {
                  EmailEvent emailEvent = (EmailEvent)event;
                  System.out.println("郵件地址:" + emailEvent.getAddress());
                  System.our.println("郵件內(nèi)容:" + emailEvent.getText());
               } else {
                  System.our.println("容器本身事件:" + event);
               }
             }
          }
          1. 發(fā)送郵件后,觸發(fā)事件,代碼如下:
          public class SpringTest {
             public static void main(String args[]){
               ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
               //創(chuàng)建一個(gè)ApplicationEvent對(duì)象
               EmailEvent event = new EmailEvent("hello","[email protected]","This is a test");
               //主動(dòng)觸發(fā)該事件
               context.publishEvent(event);
             }
          }

          2、SpringBootCommandLineRunner接口

          當(dāng)容器初始化完成之后會(huì)調(diào)用CommandLineRunner中的run()方法,同樣能夠達(dá)到容器啟動(dòng)之后完成一些事情。這種方式和ApplicationListener相比更加靈活,如下:

          • 不同的CommandLineRunner實(shí)現(xiàn)可以通過(guò)@Order()指定執(zhí)行順序
          • 可以接收從控制臺(tái)輸入的參數(shù)。

          下面自定義一個(gè)實(shí)現(xiàn)類,代碼如下:

          @Component
          @Slf4j
          public class CustomCommandLineRunner implements CommandLineRunner {

              /**
               * @param args 接收控制臺(tái)傳入的參數(shù)
               */

              @Override
              public void run(String... args) throws Exception {
                  log.debug("從控制臺(tái)接收參數(shù)>>>>"+ Arrays.asList(args));
              }
          }

          運(yùn)行這個(gè)jar,命令如下:

          java -jar demo.jar aaa bbb ccc

          以上命令中傳入了三個(gè)參數(shù),分別是aaabbb、ccc,這三個(gè)參數(shù)將會(huì)被run()方法接收到。如下圖:

          源碼分析

          讀過(guò)我的文章的鐵粉都應(yīng)該知道CommandLineRunner是如何執(zhí)行的,原文:頭禿系列,二十三張圖帶你從源碼分析Spring Boot 啟動(dòng)流程~

          Spring Boot 加載上下文的入口在org.springframework.context.ConfigurableApplicationContext()這個(gè)方法中,如下圖:

          調(diào)用CommandLineRunner在callRunners(context, applicationArguments);這個(gè)方法中執(zhí)行,源碼如下圖:

          3、SpringBootApplicationRunner接口

          ApplicationRunnerCommandLineRunner都是Spring Boot 提供的,相對(duì)于CommandLineRunner來(lái)說(shuō)對(duì)于控制臺(tái)傳入的參數(shù)封裝更好一些,可以通過(guò)鍵值對(duì)來(lái)獲取指定的參數(shù),比如--version=2.1.0

          此時(shí)運(yùn)行這個(gè)jar命令如下:

          java -jar demo.jar --version=2.1.0 aaa bbb ccc

          以上命令傳入了四個(gè)參數(shù),一個(gè)鍵值對(duì)version=2.1.0,另外三個(gè)是分別是aaa、bbbccc。

          同樣可以通過(guò)@Order()指定優(yōu)先級(jí),如下代碼:

          @Component
          @Slf4j
          public class CustomApplicationRunner implements ApplicationRunner {
              @Override
              public void run(ApplicationArguments args) throws Exception {
                  log.debug("控制臺(tái)接收的參數(shù):{},{},{}",args.getOptionNames(),args.getNonOptionArgs(),args.getSourceArgs());
              }
          }

          通過(guò)以上命令運(yùn)行,結(jié)果如下圖:

          源碼分析

          CommandLineRunner一樣,同樣在callRunners()這個(gè)方法中執(zhí)行,源碼如下圖:

          4、@PostConstruct注解

          前三種針對(duì)的是容器的初始化完成之后做的一些事情,@PostConstruct這個(gè)注解是針對(duì)Bean的初始化完成之后做一些事情,比如注冊(cè)一些監(jiān)聽(tīng)器...

          @PostConstruct注解一般放在Bean的方法上,一旦Bean初始化完成之后,將會(huì)調(diào)用這個(gè)方法,代碼如下:

          @Component
          @Slf4j
          public class SimpleExampleBean {

              @PostConstruct
              public void init(){
                  log.debug("Bean初始化完成,調(diào)用...........");
              }
          }

          5、@Bean注解中指定初始化方法

          這種方式和@PostConstruct比較類似,同樣是指定一個(gè)方法在Bean初始化完成之后調(diào)用。

          新建一個(gè)Bean,代碼如下:

          @Slf4j
          public class SimpleExampleBean {

              public void init(){
                  log.debug("Bean初始化完成,調(diào)用...........");
              }
          }

          在配置類中通過(guò)@Bean實(shí)例化這個(gè)Bean,不過(guò)@Bean中的initMethod這個(gè)屬性需要指定初始化之后需要執(zhí)行的方法,如下:

          @Bean(initMethod = "init")
              public SimpleExampleBean simpleExampleBean(){
                  return new SimpleExampleBean();
              }

          6、 InitializingBean接口

          InitializingBean的用法基本上與@PostConstruct一致,只不過(guò)相應(yīng)的Bean需要實(shí)現(xiàn)afterPropertiesSet方法,代碼如下:

          @Slf4j
          @Component
          public class SimpleExampleBean implements InitializingBean {

              @Override
              public void afterPropertiesSet()  {
                  log.debug("Bean初始化完成,調(diào)用...........");
              }
          }
          — 【 THE END 】—
          本公眾號(hào)全部博文已整理成一個(gè)目錄,請(qǐng)?jiān)诠娞?hào)里回復(fù)「m」獲??!

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) PDF 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)


          瀏覽 65
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲成人无码高清在线 | www.依依成人 | 亚洲免费日本精品在线观看 | 精品一区二区三区四区五区六区七区 | 亚洲搞逼|