天天看點

如何在項目啟動時就執行某些操作

參考資料:如何在項目啟動時就執行某些操作

在實際的項目開發中經常會遇到一些需要在項目啟動的時候進行初始化操作的需求,比如初始化線程池,配置某些對象的序列化和反序列化方式,加載黑名單白名單,加載權限應用,加載組織架構到緩存等等。這篇文章就來總結一下如何在項目初始化時進行一些資源操作。

方法一:@PostConstruct方法

//将黑名單從資料庫中查詢出來,并放到緩存中
@Service("phoneBlacklistCache")
public class PhoneBlacklistCache {
  public List<String> phoneBlacklist = new ArrayList<String>();
 
 @PostConstruct
  public void init(){     
    //需要進行的操作,如:查詢資料庫,寫到緩存
    }
}
           

方法二:init-method方法

1、在xml檔案裡配置bean,bean的配置中配置init-method方法(該方法配置成你想要執行的操作方法)。

<bean id="PoneBlacklistCache" class="com.xxx.cache.PhoneBlacklistCache" scope="singleton"  init-method="init"></bean>
           

2、通過@Bean注解的方式

@Service("phoneBlacklistCache")
public class PhoneBlacklistCache {
  public List<String> phoneBlacklist = new ArrayList<String>();
  
@Bean(initMethod = “init”)
  public void init(){     
    //需要進行的操作,如:查詢資料庫,寫到緩存
    }
}
           

方法三:InitializingBean方法

讓相應的類實作InitializingBean接口,重寫InitializingBean接口的afterPropertiesSet方法即可。

public class PhoneBlacklistCache implements InitializingBean{
      public List<String> phoneBlacklist = new ArrayList<String>();
      @Override
      public void afterPropertiesSet() throws Exception {     
       //需要進行的操作,比如查詢資料庫,寫到緩存
     }
 }
           

方法四:quartz方法

将定時任務(如:SimpleTriggerBean等)配置成項目啟動後立即執行,且重複執行次數配置成0次,不重複執行,即可達到項目啟動時執行一些操作的目的。

方法五:在springboot啟動類的main方法中執行

@SpringBootApplication
public class TestApplication {
	public static void main(String[] args) {
		System.out.println(" doSomething……");
		SpringApplication.run(CommandLineRunnerApplication.class, args);
		System.out.println(" doSomething……");
	}
}
           

方法六:實作CommandLineRunner/ApplicationRunner接口

CommandLineRunner 接口的 Component 會在所有 SpringBeans都初始化之後, SpringApplication.run()之前執行,非常适合在應用程式啟動之初進行一些資料初始化的工作。

@SpringBootApplication
public class TestCommandLineRunnerApplication {
	public static void main(String[] args) {
		System.out.println("The service to start.");
		SpringApplication.run(CommandLineRunnerApplication.class, args);
		System.out.println("The service has started.");
	}
}
           

實作CommandLineRunner接口

@Component
public class Runner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The Runner start to initialize ...");
}
}
           

控制台列印結果

...
The service to start.
 
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.0.RELEASE)
...
2018-04-21 22:21:34.706  INFO 27016 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-04-21 22:21:34.710  INFO 27016 --- [           main] com.xxx.TestCommandLineRunnerApplication     : Started TestCommandLineRunnerApplication in 3.796 seconds (JVM running for 5.128)
The Runner start to initialize ...
           

如果我們在啟動容器的時候需要初始化很多資源,并且初始化資源互相之間有序,那如何保證不同的 CommandLineRunner的執行順序呢?Spring Boot 也給出了解決方案。那就是使用 @Order 注解。

實作類一

@Component
@Order(1)
public class OrderRunner1 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The OrderRunner1 start to initialize ...");
    }
}
           

實作類二

@Component
@Order(2)
public class OrderRunner2 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The OrderRunner2 start to initialize ...");
    }
}
           

控制台執行結果如下

...
The service to start.
 
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.0.RELEASE)
...
2018-04-21 22:21:34.706  INFO 27016 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-04-21 22:21:34.710  INFO 27016 --- [           main] com.xxx.TestCommandLineRunnerApplication     : Started TestCommandLineRunnerApplication in 3.796 seconds (JVM running for 5.128)
The OrderRunner1 start to initialize ...
The OrderRunner2 start to initialize ...
The Runner start to initialize ...
           

通過控制台的輸出我們發現,添加 @Order 注解的實作類最先執行,并且@Order()裡面的值越小啟動越早。

對比:

相同點:這兩種方法提供的目的是為了滿足,在項目啟動的時候立刻執行某些方法。我們可以通過實作ApplicationRunner和CommandLineRunner,來實作,他們都是在SpringApplication 執行之後開始執行的。

不同點:CommandLineRunner接口可以用來接收字元串數組的指令行參數,ApplicationRunner 是使用ApplicationArguments 用來接收參數的 【根據業務場景靈活運用】

ApplicationRunner源碼如下:

public interface ApplicationRunner {

    void run(ApplicationArguments var1) throws Exception;
}
           

CommandLineRunner源碼如下

public interface CommandLineRunner {

   void run(String... var1) throws Exception;
}