Spring常見擴充總結
通常,應用程式開發人員不需要子類化ApplicationContext實現類。相反,可以通過插入特殊整合介面的實現來擴充套件Spring IoC容器。下圖展示了Spring Bean的生命週期。而在這其中,與一些擴充點是非常相關的。也就是說,這些擴充點作用了Bean的生命週期中。(在看下面的擴充點的時候,可以結合這個圖,觀察擴充點所處於的生命週期位置)
1. FactoryBean(用於自定義例項化邏輯)
FactoryBean
通常是用來建立比較複雜的bean,一般的bean 直接用xml配置即可,但如果一個bean的建立過程中涉及到很多其他的bean 和複雜的邏輯,用xml配置比較困難,這時可以考慮用FactoryBean。
- 定義需要建立的Bean
public class Tool {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Tool(int id) {
this.id = id;
}
}
- 實現FactoryBean
public class ToolFactory implements FactoryBean<Tool> {
private int factoryId;
private int toolId;
//獲取所建立的Bean
@Override
public Tool getObject() throws Exception {
return new Tool(toolId);
}
//獲取物件型別
@Override
public Class<?> getObjectType() {
return Tool.class;
}
public int getFactoryId() {
return factoryId;
}
//設定是否單例
@Override
public boolean isSingleton() {
return false;
}
public void setFactoryId(int factoryId) {
this.factoryId = factoryId;
}
public int getToolId() {
return toolId;
}
public void setToolId(int toolId) {
this.toolId = toolId;
}
}
建立Tool
這個Bean的具體過程都交給了ToolFactory
來管理,也就是建立的細節都有它控制.
- 把
FactoryBean
建立Bean交給容器管理。
@Configuration
public class FactoryBeanAppConfig implements InitializingBean,BeanPostProcessor {
//注入到容器裡面
@Bean(name="tool")
public ToolFactory toolFactory() {
ToolFactory factory = new ToolFactory();
factory.setFactoryId(7070);
factory.setToolId(2);
return factory;
}
- 通過
name = "&tool"
來獲取到ToolFactory
,因為ToolFactory
本身也是Bean,由Spring容器管理.
//注入Tool
@Autowired
Tool tool;
//注入ToolFactory
@Resource(name = "&tool")
ToolFactory toolFactory;
2. InitializingBean和DisposableBean
IInitializingBean
和DisposableBean
中前者是在容器對Bean必要的屬性做了初始化後,再做後續的初始化。後者是容器對Bean銷燬之前做一個回撥。
- InitializingBean
InitializingBean
只有一個方法,允許你在初始化之後做個回撥。
void afterPropertiesSet() throws Exception;
通常來說,不推薦使用InitializingBean
,因為它和Spring耦合太緊密了。推薦使用 @PostConstruct
註解 或者一個具體的 POJO 初始化方法。推薦使用的與InitializingBean
效果是一樣的,但是前者就沒有和Spring耦合。
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
而 @PostConstruct
註解 則需要在支援Servlet2.5的容器使用。
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
這三種方法的效果是一樣的,但是當同時配置的時候,按照Spring Bean的生命週期,執行的順序如下:
- 使用
@PostConstruct
註解的方法。 -
InitializingBean
中的afterPropertiesSet()
方法。 - 自定義的
init()
方法。
對應的,銷燬中@PreDestroy
,DisposableBean
,自定義的destroy()
效果一樣,執行順序與初始化的順序對應一樣。這兩類在初始化之前和銷燬之前的回撥通常用於快取的初始載入和快取的清除這樣的場景。
3. BeanNameAware,BeanFactoryAware,ApplicationContextAware
-
BeanNameAware
使得物件能夠感知到bean的名稱。通常用於把beanName記錄在日誌。 -
BeanFactoryAware
使得我們可以獲取到BeanFactory
,進而可以獲取到bean,或者判斷bean是否是單例。 -
ApplicationContextAware
使得我們獲取到ApplicationContext
的具體實現類這個容器。這個ApplicationContext
比BeanFactory
功能更強大。
使用 BeanNameAware
,BeanFactoryAware
,ApplicationContextAware
值需要實現介面裡面相應的方法即可。通常來說,定義一個類變數來分別紀錄下感知的的Name,BeanFactory,ApplicationContext即可。
@Override
public void setBeanName(String s) {
System.out.println(s);
System.out.println("setBeanName方法被呼叫");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory.containsBean("person"));
System.out.println(beanFactory.isSingleton("person"));
System.out.println("setBeanFactory被呼叫,beanFactory");
}
//功能比beanFactory功能更強大些
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(applicationContext.getId());
System.out.println(applicationContext.containsBean("person"));
System.out.println("setApplicationContext被呼叫");
}
在大多數情況下,我們應該避免使用這些Aware
介面,因為它和Spring耦合太多。
4. BeanPostProcessor,BeanFactoryPostProcessor
-
BeanPostProcessor
是在整個bean已經建立,並且設定好類成員屬性之後,即spring容器已經例項化一個bean後。通過回撥方法去實現自定義的例項邏輯.通常用於檢查bean屬性的有效性,每個bean在初始化(init-method,InitializingBean等初始化方法)前後,都會回撥BeanPostProcessor
中的方法。 -
BeanFactoryPostProcessor
主要用於改變bean的Metadata。Spring容器允許BeanFactoryPostProcessor
去讀取配置元屬性,並改變它。它在BeanPostProcessor
之前執行。
public class MyBeanPostProcessor implements BeanPostProcessor,BeanFactoryPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if(bean instanceof Person) {
((Person) bean).setName("sb");
}
System.out.println("postProcessBeforeInitialization被呼叫");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization被呼叫");
return bean;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor被呼叫");
}
}
這樣,SpringBean的生命週期就被串聯起來了。如下
首先容器啟動後,會對scope為singleton且非懶載入的bean進行例項化,
按照Bean定義資訊配置資訊,注入所有的屬性,
如果Bean實現了BeanNameAware介面,會回撥該介面的setBeanName()方法,傳入該Bean的id,此時該Bean就獲得了自己在配置檔案中的id,
如果Bean實現了BeanFactoryAware介面,會回撥該介面的setBeanFactory()方法,傳入該Bean的BeanFactory,這樣該Bean就獲得了自己所在的BeanFactory,
如果Bean實現了ApplicationContextAware介面,會回撥該介面的setApplicationContext()方法,傳入該Bean的ApplicationContext,這樣該Bean就獲得了自己所在的ApplicationContext,
如果有Bean實現了BeanPostProcessor介面,則會回撥該介面的postProcessBeforeInitialzation()方法,
如果Bean實現了InitializingBean介面,則會回撥該介面的afterPropertiesSet()方法,(初始化之一)
如果Bean配置了init-method方法,則會執行init-method配置的方法,(初始化之一)
如果有Bean實現了BeanPostProcessor介面,則會回撥該介面的postProcessAfterInitialization()方法,
經過流程9之後,就可以正式使用該Bean了,對於scope為singleton的Bean,Spring的ioc容器中會快取一份該bean的例項,而對於scope為prototype的Bean,每次被呼叫都會new一個新的物件,期生命週期就交給呼叫方管理了,不再是Spring容器進行管理了
容器關閉後,如果Bean實現了DisposableBean介面,則會回撥該介面的destroy()方法,
如果Bean配置了destroy-method方法,則會執行destroy-method配置的方法,至此,整個Bean的生命週期結束。
相關文章
- Spring Cloud中,Feign常見問題總結SpringCloud
- golang 常見疑惑總結Golang
- python常見漏洞總結Python
- Vue 常見問題總結Vue
- TCP常見問題總結TCP
- mysql常見問題總結MySql
- Kubernetes 常見問題總結
- Flink 常見問題總結
- Spring JPA 擴充Spring
- 【軟體架構篇】常見可擴充套件模式架構套件模式
- js常見函式總結(一)JS函式
- Webpack常見面試題總結Web面試題
- Shell:常見錯誤總結(一)
- 常見排序演算法總結排序演算法
- 常見顏色空間總結
- larabbs 使用的一些擴充總結
- 常見線纜介面型別總結型別
- Javascript 常見的迴圈方式總結JavaScript
- 四種常見NLP框架使用總結框架
- Java基礎之常見API總結JavaAPI
- Web中介軟體常見漏洞總結Web
- 前端常見面試題少量總結前端面試題
- 常見壓縮演算法總結演算法
- leetcode 常見題型程式碼總結LeetCode
- spring bean 擴充套件方式SpringBean套件
- 使用Kotlin擴充套件函式擴充套件Spring Data案例Kotlin套件函式Spring
- 資料庫常見面試題總結資料庫面試題
- 總結下常見佈局解決方案
- 幾種常見排序演算法總結排序演算法
- Android常見記憶體洩漏總結Android記憶體
- PbootCMS網站常見錯誤提示總結boot網站
- 常見Java面試知識點總結Java面試
- MySQL常見面試題總結[精讀]MySql面試題
- ES6常見面試題總結面試題
- 擴充_ETHREAD結構thread
- RabbitMQ實戰:擴充套件介紹與系列總結MQ套件
- MyBatis學習總結(24)——Mybatis常見問題彙總MyBatis
- Spring容器擴充套件機制Spring套件