Spring啟動時實現初始化有哪些方式?
一、Spring啟動時實現初始化的幾種方式
準確的說是spring容器實例化完成後,幾種初始化的方式。為什麼這麼說呢?下看面示例:
@Slf4j @Component public class InitBeanDemo { @Autowired private Environment env; public InitBeanDemo() { log.info("DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); }
示例是在bean的構造方法裡做一些初始化的工作,示例比較簡單隻做瞭日志打印。是理想很豐滿,現實很骨感,報錯瞭:Constructor threw exception; nested exception is java.lang.NullPointerException。
原因是,Environment尚未初始化完成。
接下來我們來探索一下 有哪些初始化方式能滿足上面示例的需求。
二、構造方法裡初始化
可以正常運行,在所有初始化方式裡執行時機最早。原理是在InitBeanDemo實例化前就實例化瞭Environment。
@Component public class InitBeanDemo { private final Environment env; @Autowired public InitBeanDemo (Environment environment) { this.env = environment; log.info("Constructor DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("Constructor ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); } }
三、常規三件套
常規三件套:@PostConstruct、InitializingBean、initMethod。 如果你願意的話,三種方式可以在同一個Bean下同時使用,執行的優先級@PostConstruct > InitializingBean > initMethod。
@PostConstruct註解
在一個可以被掃描到Bean裡,添加一個public void xxx()方法並加上@PostConstruct註解,方法裡編寫需要初始化的邏輯。
同一個應用程序裡可以有多個@PostConstruct註解,同一個Bean裡也可以有多個@PostConstruct註解。
@Slf4j @Component public class InitBeanDemo { @Autowired private Environment env; @PostConstruct public void init() { log.info("@PostConstruct DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("@PostConstruct ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); }
實現InitializingBean接口
實現InitializingBean接口,在afterPropertiesSet() 方法裡編寫需要初始化的邏輯。
同一個應用程序裡可以有多個實現InitializingBean接口的類,執行時機會按類名的自然順序排序。
@Slf4j @Component public class InitBeanDemo implements InitializingBean { @Autowired private Environment env; @Override public void afterPropertiesSet() throws Exception { log.info("InitializingBean DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("InitializingBean ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); } }
指定Bean的initMethod方法
使用@Bean註解的initMethod屬性可用於Bean的初始化後執行的方法。initMethod必須是public void 的無參構造方法。
@Slf4j public class InitBeanDemo implements InitializingBean { @Autowired private Environment env; public void initMethod() { log.info("initMethod DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("initMethod ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); }
@Configuration public class InitBeanConfig { @Bean(initMethod="initMethod") public InitBeanDemo initBeanDemo () { return new InitBeanDemo(); } }
等同於 在XML 配置中的init-method屬性:
<bean id="initBeanDemo" class="com.xxx.InitBeanDemo" init-method="initMethod"></bean>
四、自定義ApplicationListener監聽
兩種方式,一種實現接口,另一種使用註解。
實現ApplicationListener接口
監聽ContextRefreshedEvent事件。
@Slf4j @Component public class InitBeanDemo implements ApplicationListener<ContextRefreshedEvent>{ @Autowired private Environment env; @Override public void onApplicationEvent(ContextRefreshedEvent event) { log.info("ApplicationListener DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("ApplicationListener ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); } }
@EventListener註釋
方法參數裡指定ContextRefreshedEvent事件。
@Slf4j @Component public class InitBeanDemo { @Autowired private Environment env; @EventListener public void onApplicationEvent2(ContextRefreshedEvent event) { log.info("@EventListener DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("@EventListener ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); } }
五、Spring Boot提供的初始化接口
ApplicationRunner接口
@Slf4j @Component public class InitBeanDemo implements ApplicationRunner { @Autowired private Environment env; @Override public void run(ApplicationArguments args) throws Exception { log.info("ApplicationRunner: {}", args); log.info("ApplicationRunner: {}", args.getOptionNames()); log.info("ApplicationRunner DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("ApplicationRunner ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); } }
CommandLineRunner接口
可以在同一個應用程序上下文中定義多個CommandLineRunner bean,並且可以使用@Ordered接口或@Order註釋進行排序。
@Slf4j @Component public class InitBeanDemo implements CommandLineRunner { @Autowired private Environment env; @Override public void run(String... args) throws Exception { log.info("CommandLineRunner: {}", args); log.info("CommandLineRunner DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles())); log.info("CommandLineRunner ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles())); } }
在同一個Bean裡使用以上初始化方式的執行先後順序
在同一個Bean裡使用以上初始化方式,運行的日志片段:
2021-06-07 11:24:41|INFO |main|c.c.s.s.t.ConstructorInitDemo|Constructor DefaultProfiles: [default]
2021-06-07 11:24:41|INFO |main|c.c.s.s.t.ConstructorInitDemo|Constructor ActiveProfiles: [sit]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|@PostConstruct DefaultProfiles: [default]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|@PostConstruct ActiveProfiles: [sit]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|InitializingBean DefaultProfiles: [default]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|InitializingBean ActiveProfiles: [sit]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|initMethod DefaultProfiles: [default]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|initMethod ActiveProfiles: [sit]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|@EventListener DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|@EventListener ActiveProfiles: [sit]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationListener DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationListener ActiveProfiles: [sit]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner: org.springframework.boot.DefaultApplicationArguments@68bef3df
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner: []
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner ActiveProfiles: [sit]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|CommandLineRunner: {}
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|CommandLineRunner DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|CommandLineRunner ActiveProfiles: [sit]
也即 整篇文章整理的先後順序。
到此這篇關於Spring啟動時實現初始化有哪些方式?的文章就介紹到這瞭,更多相關Spring初始化內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 使用Spring啟動時運行自定義業務
- Springboot啟動執行特定代碼的方式匯總
- 使用spring容器在初始化Bean時前和後的操作
- spring註解如何為bean指定InitMethod和DestroyMethod
- 淺談SpringBoot中的Bean初始化方法 @PostConstruct