成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

七種方式,教你在SpringBoot初始化時搞點事情!

開發(fā) 后端
我們經(jīng)常需要在容器啟動的時候做一些鉤子動作,比如注冊消息消費者,監(jiān)聽配置等,今天就總結(jié)下SpringBoot留給開發(fā)者的7個啟動擴展點。

[[390889]]

 我們經(jīng)常需要在容器啟動的時候做一些鉤子動作,比如注冊消息消費者,監(jiān)聽配置等,今天就總結(jié)下SpringBoot留給開發(fā)者的7個啟動擴展點。

容器刷新完成擴展點

1、監(jiān)聽容器刷新完成擴展點ApplicationListener<ContextRefreshedEvent>

基本用法

熟悉Spring的同學(xué)一定知道,容器刷新成功意味著所有的Bean初始化已經(jīng)完成,當(dāng)容器刷新之后Spring將會調(diào)用容器內(nèi)所有實現(xiàn)了ApplicationListener<ContextRefreshedEvent>的Bean的onApplicationEvent方法,應(yīng)用程序可以以此達(dá)到監(jiān)聽容器初始化完成事件的目的。 

  1. @Component  
  2. public class StartupApplicationListenerExample implements   
  3.   ApplicationListener<ContextRefreshedEvent> {  
  4.     private static final Logger LOG   
  5.       = Logger.getLogger(StartupApplicationListenerExample.class);  
  6.     public static int counter;  
  7.     @Override public void onApplicationEvent(ContextRefreshedEvent event) {  
  8.         LOG.info("Increment counter");  
  9.         counter++;  
  10.     }  

易錯的點

這個擴展點用在web容器中的時候需要額外注意,在web 項目中(例如spring mvc),系統(tǒng)會存在兩個容器,一個是root application context,另一個就是我們自己的context(作為root application context的子容器)。如果按照上面這種寫法,就會造成onApplicationEvent方法被執(zhí)行兩次。解決此問題的方法如下: 

  1. @Component  
  2. public class StartupApplicationListenerExample implements   
  3.   ApplicationListener<ContextRefreshedEvent> {  
  4.     private static final Logger LOG   
  5.       = Logger.getLogger(StartupApplicationListenerExample.class);  
  6.     public static int counter;  
  7.     @Override public void onApplicationEvent(ContextRefreshedEvent event) {  
  8.         if (event.getApplicationContext().getParent() == null) {  
  9.             // root application context 沒有parent  
  10.             LOG.info("Increment counter");  
  11.             counter++;  
  12.         }  
  13.     }  

高階玩法

當(dāng)然這個擴展還可以有更高階的玩法:自定義事件,可以借助Spring以最小成本實現(xiàn)一個觀察者模式:

  •  先自定義一個事件: 
  1. public class NotifyEvent extends ApplicationEvent {  
  2.     private String email;  
  3.     private String content;  
  4.     public NotifyEvent(Object source) {  
  5.         super(source);  
  6.     }  
  7.     public NotifyEvent(Object source, String email, String content) { 
  8.          super(source);  
  9.         this.email = email;  
  10.         this.content = content;  
  11.     }  
  12.     // 省略getter/setter方法  
  •  注冊一個事件監(jiān)聽器 
  1. @Component  
  2. public class NotifyListener implements ApplicationListener<NotifyEvent> {  
  3.     @Override  
  4.     public void onApplicationEvent(NotifyEvent event) {  
  5.         System.out.println("郵件地址:" + event.getEmail());  
  6.         System.out.println("郵件內(nèi)容:" + event.getContent());  
  7.     }  
  •  發(fā)布事件 
  1. @RunWith(SpringRunner.class)  
  2. @SpringBootTest  
  3. public class ListenerTest {  
  4.     @Autowired  
  5.     private WebApplicationContext webApplicationContext;  
  6.     @Test  
  7.     public void testListener() {  
  8.         NotifyEvent event = new NotifyEvent("object", "abc@qq.com", "This is the content");  
  9.         webApplicationContext.publishEvent(event);  
  10.     }  
  •  執(zhí)行單元測試可以看到郵件的地址和內(nèi)容都被打印出來了

2、SpringBoot的CommandLineRunner接口

當(dāng)容器上下文初始化完成之后,SpringBoot也會調(diào)用所有實現(xiàn)了CommandLineRunner接口的run方法,下面這段代碼可起到和上文同樣的作用: 

  1. @Component  
  2. public class CommandLineAppStartupRunner implements CommandLineRunner {  
  3.     private static final Logger LOG =  
  4.       LoggerFactory.getLogger(CommandLineAppStartupRunner.class);  
  5.     public static int counter;  
  6.     @Override  
  7.     public void run(String...args) throws Exception { 
  8.         LOG.info("Increment counter");  
  9.         counter++;  
  10.     }  

對于這個擴展點的使用有額外兩點需要注意:

  • 多個實現(xiàn)了CommandLineRunner的Bean的執(zhí)行順序可以根據(jù)Bean上的@Order注解調(diào)整
  • 其run方法可以接受從控制臺輸入的參數(shù),跟ApplicationListener<ContextRefreshedEvent>這種擴展相比,更加靈活 
  1. // 從控制臺輸入?yún)?shù)示例  
  2. java -jar CommandLineAppStartupRunner.jar abc abcd 

3、SpringBoot的ApplicationRunner接口

這個擴展和SpringBoot的CommandLineRunner接口的擴展類似,只不過接受的參數(shù)是一個ApplicationArguments類,對控制臺輸入的參數(shù)提供了更好的封裝,以--開頭的被視為帶選項的參數(shù),否則是普通的參數(shù) 

  1. @Component  
  2. public class AppStartupRunner implements ApplicationRunner {  
  3.     private static final Logger LOG =  
  4.       LoggerFactory.getLogger(AppStartupRunner.class);  
  5.     public static int counter;  
  6.     @Override  
  7.     public void run(ApplicationArguments args) throws Exception {  
  8.         LOG.info("Application started with option names : {}",   
  9.           args.getOptionNames());  
  10.         LOG.info("Increment counter");  
  11.         counter++;  
  12.     }  

比如:

  1. java -jar CommandLineAppStartupRunner.jar abc abcd --autho=mark verbose 

Bean初始化完成擴展點

前面的內(nèi)容總結(jié)了針對容器初始化的擴展點,在有些場景,比如監(jiān)聽消息的時候,我們希望Bean初始化完成之后立刻注冊監(jiān)聽器,而不是等到整個容器刷新完成,Spring針對這種場景同樣留足了擴展點:

1、@PostConstruct注解 

  1. @PostConstruct注解一般放在Bean的方法上,被@PostConstruct修飾的方法會在Bean初始化后馬上調(diào)用:  
  2. @Component  
  3. public class PostConstructExampleBean {  
  4.     private static final Logger LOG   
  5.       = Logger.getLogger(PostConstructExampleBean.class);  
  6.     @Autowired  
  7.     private Environment environment;  
  8.     @PostConstruct  
  9.     public void init() {  
  10.         LOG.info(Arrays.asList(environment.getDefaultProfiles()));  
  11.     }  

2、 InitializingBean接口

InitializingBean的用法基本上與@PostConstruct一致,只不過相應(yīng)的Bean需要實現(xiàn)afterPropertiesSet方法 

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

3、@Bean注解的初始化方法

通過@Bean注入Bean的時候可以指定初始化方法:

Bean的定義 

  1. public class InitMethodExampleBean {  
  2.     private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class);  
  3.     @Autowired  
  4.     private Environment environment;  
  5.     public void init() {  
  6.         LOG.info(Arrays.asList(environment.getDefaultProfiles()));  
  7.     }  

Bean注入 

  1. @Bean(initMethod="init" 
  2. public InitMethodExampleBean initMethodExampleBean() {  
  3.     return new InitMethodExampleBean();  

4、通過構(gòu)造函數(shù)注入

Spring也支持通過構(gòu)造函數(shù)注入,我們可以把搞事情的代碼寫在構(gòu)造函數(shù)中,同樣能達(dá)到目的 

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

Bean初始化完成擴展點執(zhí)行順序?

可以用一個簡單的測試: 

  1. @Component  
  2. @Scope(value = "prototype" 
  3. public class AllStrategiesExampleBean implements InitializingBean {  
  4.     private static final Logger LOG   
  5.       = Logger.getLogger(AllStrategiesExampleBean.class);  
  6.     public AllStrategiesExampleBean() {  
  7.         LOG.info("Constructor");  
  8.     }  
  9.     @Override  
  10.     public void afterPropertiesSet() throws Exception {  
  11.         LOG.info("InitializingBean");  
  12.     }  
  13.     @PostConstruct  
  14.     public void postConstruct() { 
  15.         LOG.info("PostConstruct");  
  16.     }  
  17.     public void init() {  
  18.         LOG.info("init-method");  
  19.     }  

實例化這個Bean后輸出: 

  1. [main] INFO o.b.startup.AllStrategiesExampleBean - Constructor  
  2. [main] INFO o.b.startup.AllStrategiesExampleBean - PostConstruct  
  3. [main] INFO o.b.startup.AllStrategiesExampleBean - InitializingBean  
  4. [main] INFO o.b.startup.AllStrategiesExampleBean - init-method  

 

責(zé)任編輯:龐桂玉 來源: Java知音
相關(guān)推薦

2025-01-21 08:00:00

限流微服務(wù)算法

2018-06-10 16:31:12

2017-06-14 16:44:15

JavaScript原型模式對象

2010-09-17 17:51:04

2022-07-01 08:00:44

異步編程FutureTask

2022-03-18 14:33:22

限流算法微服務(wù)

2022-12-23 10:55:09

CIO方式團(tuán)隊

2025-02-24 16:00:00

SpringBoot定時任務(wù)開發(fā)

2010-10-15 10:02:01

Mysql表類型

2025-05-13 08:20:58

2021-07-23 17:15:12

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

2020-01-16 12:20:03

人工智能AI稅收

2023-09-07 10:39:25

AI供應(yīng)鏈

2023-07-06 10:36:51

人工智能

2023-09-11 14:26:44

智能技術(shù)人工智能

2023-01-03 13:43:55

團(tuán)隊首席信息官

2025-04-28 08:39:48

Spring初始化開發(fā)

2022-06-09 18:09:59

農(nóng)業(yè)物聯(lián)網(wǎng)IOT

2023-10-19 17:30:50

2022-05-10 08:08:01

find命令Linux
點贊
收藏

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

主站蜘蛛池模板: 一级少妇女片 | 欧美日韩国产一区二区三区 | 男女午夜免费视频 | 激情毛片 | 国产黄视频在线播放 | 国产一区二区三区 | 6080亚洲精品一区二区 | 91在线视频播放 | 欧美一区二不卡视频 | 欧美黄视频 | 国产成人精品免高潮在线观看 | 午夜资源| 日本激情视频在线播放 | 在线免费观看a级片 | 在线视频日韩精品 | 国产精品视频一二三区 | 欧美黄色网 | 国产伦精品一区二区三区照片91 | 国产欧美精品一区二区色综合 | 中文字幕高清在线 | 国产精品99999 | 国产剧情一区二区三区 | 欧美a在线看 | 日本一区高清 | 亚洲欧洲成人av每日更新 | 欧美日韩视频在线 | 国产剧情久久 | 高清久久| 国产精品a久久久久 | 一区影院 | 欧美精品91爱爱 | aaaa日韩| 久久国内精品 | 午夜电影网 | 午夜精品久久久久久久99黑人 | 精品国产乱码久久久久久果冻传媒 | 国产黄色在线观看 | 一区二区三区在线免费观看 | 国产精品国产成人国产三级 | 一区二区三区高清 | 国产激情视频在线观看 |