總結(jié)Bean的三種自定義初始化和銷毀方法
Bean三種自定義初始化和銷毀
一. 三種方法概述
在配置類中指定 @Bean(initMethod = “init”,destroyMethod = “destory”)注解
實現(xiàn)InitializingBean接口并重寫其afterPropertiesSet方法,實現(xiàn)DisposableBean接口并重寫destroy方法
利用java的JSR250規(guī)范中的@PostConstruct標注在init方法上,@PreDestroy標注在destroy方法上
二. 方法詳述
1. 方法1:配置類中指定
示例代碼
public class CarA {
public CarA() {
System.out.println("CarA。。。構(gòu)造函數(shù)");
}
public void initCarA(){
System.out.println("CarA的init()方法");
}
public void destroyCarA(){
System.out.println("CarA的destroy()方法");
}
}
@Configuration
public class ConfigTest {
@Bean(initMethod = "initCarA",destroyMethod = "destroyCarA")
public CarA carA(){
return new CarA();
}
}
執(zhí)行結(jié)果
CarA。。。構(gòu)造函數(shù)
CarA的init()方法服務啟動
CarA的destroy()方法
2. 方法2:實現(xiàn)接口并重寫方法
2.1 示例代碼
public class CarB implements InitializingBean, DisposableBean {
public CarB() {
System.out.println("CarB。。。構(gòu)造函數(shù)");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("CarB。。。afterPropertiesSet()方法執(zhí)行");
}
@Override
public void destroy() throws Exception {
System.out.println("CarB。。。destroy()方法執(zhí)行");
}
}
@Configuration
public class ConfigTest {
@Bean
public CarB carB(){
return new CarB();
}
}
執(zhí)行結(jié)果
CarB。。。構(gòu)造函數(shù)
CarB。。。afterPropertiesSet()方法執(zhí)行服務啟動
CarB。。。destroy()方法執(zhí)行
2.2 概述
Spring 開放了擴展接口,允許我們自定義 bean 的初始化和銷毀方法。即當 Spring 容器在 bean 進行到相應的生命周期階段時,會自動調(diào)用我們自定義的初始化和銷毀方法。這兩個擴展接口是 InitializingBean 和 DisposableBean 。
InitializingBean 接口說明:該接口為 bean 提供了 bean 屬性初始化后的處理方法,它只有 afterPropertiesSet 一個方法,凡是實現(xiàn)此接口的類,在 bean 的屬性初始化后都會執(zhí)行該方法。
package org.springframework.beans.factory;
public interface InitializingBean {
? ? void afterPropertiesSet() throws Exception;
}DisposableBean 接口說明:該接口為單例 bean 提供了在容器銷毀 bean 時的處理方法,它只有 destroy 一個方法,凡是實現(xiàn)此接口的類,在 bean 被銷毀時都會執(zhí)行該方法。
package org.springframework.beans.factory;
public interface DisposableBean {
? ? void destroy() throws Exception;
}2.3 方法1 && 方法2
- 相同點:都是在 bean 屬性初始化之后需要執(zhí)行的初始化方法。
- 不同點
方法1:代碼不與Spring耦合;執(zhí)行效率較低(通過反射來執(zhí)行initMethod 方法)
方法2:代碼與Spring緊耦合;速度更快(將 bean 強制轉(zhuǎn)換成 InitializingBean 接口類型,然后直接調(diào)用 afterPropertiesSet 方法)
- 說明:afterPropertiesSet 和 initMethod 可以同時存在,但是 afterPropertiesSet 方法是在 initMethod 方法之前執(zhí)行的。
- 一個 bean 從創(chuàng)建到初始化的過程總結(jié)
通過構(gòu)造器創(chuàng)建 bean
屬性注入
執(zhí)行 afterPropertiesSet 方法
執(zhí)行 initMethod 方法
3. 方法3:利用java的JSR250規(guī)范
代碼示例
public class CarC {
public CarC() {
System.out.println("CarC。。。構(gòu)造函數(shù)");
}
@PostConstruct
public void initCarC(){
System.out.println("CarC。。。初始化方法initCarC()");
}
@PreDestroy
public void destroyCarC(){
System.out.println("CarC。。。銷毀方法destroyCarC");
}
}
@Configuration
public class ConfigTest {
@Bean
public CarC carC(){
return new CarC();
}
}
執(zhí)行結(jié)果
CarC。。。構(gòu)造函數(shù)
CarC。。。初始化方法initCarC()服務啟動
CarC。。。銷毀方法destroyCarC
spring初始化后獲取自定義注解Bean
目的是通過注解將特定類的信息(如接口編號)與類關(guān)聯(lián),之后可通過接口編號獲取對應bean來執(zhí)行對應邏輯。
一.新建注解類
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface ServiceCode {
? ? String code() default "";?
? ? String className() default "";
}包含接口編號和beanName信息。
二.新建接口類
@ServiceCode(code = "100010", className = "echoService")
@Service("echoService")
public class EchoService {?
}三.實現(xiàn)接口ApplicationListener
來監(jiān)聽spring容器初始化完成后執(zhí)行:
@Component
@Order(1)
public class ServiceInitListener implements ApplicationListener<ContextRefreshedEvent> {
? ? private static final Logger LOGGER = LoggerFactory.getLogger(ServiceInitListener.class);?
? ? @Override
? ? public void onApplicationEvent(ContextRefreshedEvent event) {
? ? ? ? ApplicationContext applicationContext = event.getApplicationContext();
? ? ? ? //注意 需要時根容器才能通過注解獲取到bean,比如event直接獲取的容器中只有一些公共注冊bean
? ? ? ? if (applicationContext.getParent() != null) {
? ? ? ? ? ? applicationContext = applicationContext.getParent();
? ? ? ? }
? ? ? ? Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(ServiceCode.class);
? ? ? ? for (Object bean : beansWithAnnotation.values()) {
? ? ? ? ? ? ServiceCode annotation = bean.getClass().getAnnotation(ServiceCode.class);
? ? ? ? ? ? String code = annotation.code();
? ? ? ? ? ? String className = annotation.className();
? ? ? ? ? ? //注冊接口編號和beanName
? ? ? ? ? ? //在統(tǒng)一入口可通過code獲取beanName,然后通過springContext獲取對應bean執(zhí)行自定義邏輯
? ? ? ? ? ? //或者完成其他邏輯
? ? ? ? }
? ? }?
}注意:
ContextRefreshedEvent獲取到的上下文環(huán)境不是根spring容器,其中只有部分spring內(nèi)置bean,無法通過注解獲取到自定義bean,需要獲取其父容器來完成操作。我第一次獲取是beanList總為空,后來發(fā)現(xiàn)其容器內(nèi)部bean沒有自定義的service bean,獲取父容器后操作一切正常。
通過@Order注解來定制執(zhí)行順序,越小越優(yōu)先執(zhí)行。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Idea運行junit測試時報Error:[3,17]?程序包org.junit不存在的問題
這篇文章主要介紹了Idea運行junit測試時報Error:[3,17]?程序包org.junit不存在解決方法,本文給大家分享兩種解決辦法,需要的朋友可以參考下2023-03-03
Java實現(xiàn)十進制與二進制互轉(zhuǎn)的示例詳解
這篇文章主要為大家詳細介紹了Java如何實現(xiàn)十進制與二進制的互轉(zhuǎn),文中的示例代碼講解詳細,對我們學習Java有一定幫助,需要的可以參考一下2022-11-11

