最開始學(xué)習(xí)spring的入門實踐是,編寫一個xml文件,然后利用spring讀取xml文件中配置的bean。
編寫一個xml配置文件default.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="myBean" class="org.numb.springframework.ioc.bean.MyBean"/>
</beans>
編寫代碼加載這個bean,并獲取bean的實例
public void test() {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("default.xml"));
MyBean myBean = (MyBean) beanFactory.getBean("myBean");
}
至此就實現(xiàn)了springIOC加載一個bean的功能。其實在Spring代碼中提供了現(xiàn)有的測試用例,可以從測試用例入手了解源碼。注意XmlBeanFactory
自spring 3.x后逐步廢棄,使用XmlBeanDefinitionReader
替代。查看其測試類XmlBeanDefinitionReaderTests
的
withClassPathResource()
測試方法
class XmlBeanDefinitionReaderTests {
private final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
@Test
void withClassPathResource() {
// 讀取test.xml的資源文件
Resource resource = new ClassPathResource("test.xml", getClass());
// 加載資源
reader.loadBeanDefinitions(resource);
// 斷言檢查
assertThat(registry.getBeanDefinition("rod").getBeanClassName()).isEqualTo(TestBean.class.getName());
}
}
上述測試用例中,spring使用ClassPathResource
讀取bean定義test.xml
文件,然后使用XmlBeanDefinitionReader
加載資源,加載過程中會解析test.xml
,單步調(diào)試一下loadBeanDefinitions
方法的調(diào)用過程
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
// 為了適配字符集與編碼,統(tǒng)一交由EncodedResource來讀取資源
return loadBeanDefinitions(new EncodedResource(resource));
}
首先將Resource->EncodedResource來加載,EncodedResource內(nèi)部主要適配了編碼和字符集,這步不用太關(guān)心。后面使用EncodedResource加載,這里借助NamedThreadLocal
獲取當(dāng)前待加載的資源currentResources
,然后判斷資源是否能add到currentResources
的set中,如果能add說明Resource未被加載,等加載完成后再remove,避免重復(fù)加載相同的Resource。
重點在于doLoadBeanDefinitions()
方法
BeanDefinitionDocumentReader
接口根據(jù)document
讀取Bean的定義,并注冊進XmlReaderContext
中,XmlReaderContext
內(nèi)包含了xml加載的Resource
、XmlBeanDefinitionReader
等必要對象的封裝。具體bean的加載實現(xiàn)在DefaultBeanDefinitionDocumentReader
中的doRegisterBeanDefinitions()
。此處doRegisterBeanDefinitions()
會被遞歸調(diào)用,BeanDefinitionParserDelegate是類內(nèi)的對象,所以為了保證遞歸調(diào)用時類內(nèi)能夠使用正確的Delegate,此處createDelegate()
會模擬堆棧調(diào)用過程,將parent delegate傳入生成當(dāng)前的delegate。
parseBeanDefinitions()
方法是具體將xml定析的實現(xiàn)
到此為止,spring的XmlBeanDefinitionReader
將xml文件使用Resource
讀取,并解析為Bean的定義為BeanDefinition
,然后注冊入XmlReaderContext.BeanDefinitionRegistry
中,中間類的調(diào)用關(guān)系如下。
去除各個子類實現(xiàn)類,以及xxxUtil
、xxxHolder
、xxxConetxt
等工具類,簡單羅列一下頂層接口的交互過程
spring定義了幾個bean操作的頂層接口BeanDefinitionRegistry
、BeanDefinitionReader
、BeanDefinitionReader
和Resource
,上述過程完成了XML資源文件到Bean的描述對象BeanDefinition
的注冊過程,但是實際使用IOC過程中,并不是直接使用BeanDefinition
,而是直接獲取bean實例,可以查看測試用例XmlBeanDefinitionReaderTests
的doTestValidation()
方法
private void doTestValidation(String resourceName) {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
Resource resource = new ClassPathResource(resourceName, getClass());
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource);
assertThat((TestBean) factory.getBean("testBean")).isNotNull();
}
對比此處與上面的不同之處在于,此處XmlBeanDefinitionReader
的入?yún)⒂?code>SimpleBeanDefinitionRegistry變?yōu)?code>DefaultListableBeanFactory。DefaultListableBeanFactory
中提供方法factory.getBean("testBean")
直接獲取名為testBean
的bean對象,而不是獲取BeanDefinition
。
因篇幅問題不能全部顯示,請點此查看更多更全內(nèi)容
Copyright ? 2019- 91gzw.com 版權(quán)所有 湘ICP備2023023988號-2
違法及侵權(quán)請聯(lián)系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市萬商天勤律師事務(wù)所王興未律師提供法律服務(wù)