spring學習(四)xml檔案的BeanDefinition讀取
上一節中說明了spring在讀取bean時主要的方法refresh中,首先要把配置和註解的bean檔案以beanDefintion的形式快取起來,這個方法是refreshBeanFactory()
各類呼叫的程式圖如下
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) {//判斷beanFactory是否存在,存在則銷燬。 destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory();//建立一個beanFactory。這裡使用的是預設的DefaultListableBeanFactory beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory);//讀取beanDefinition synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
loadBeanDefinitions(beanFactory)是由子類實現。不同的load有不同的實現類,此處只介紹xml的讀取操作AbstractXmlApplicationContext類
1、生成一個新的XmlBeanDefinitionReader類。用於讀取配置的bean檔案
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
2、其中最主要的方法是loadBeanDefinitions(beanDefinitionReader);
這個方法中主要的實現方法:呼叫beanDefinitionReader.loadBeanDefinitions,這個方法裡又呼叫瞭如下的方法解析出Document
spring使用的是jaxp解析xml檔案,
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); return registerBeanDefinitions(doc, resource); } .... }
這裡的documentLoader是使用的預設的DefaultDocumentLoader,也可由自定義設定
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
建立一個DocumentBuilderFactory,並
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
factory.setValidating(true);
if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
// Enforce namespace aware for XSD...
factory.setNamespaceAware(true);
try {
factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
}
catch (IllegalArgumentException ex) {
ParserConfigurationException pcex = new ParserConfigurationException(
"Unable to validate using XSD: Your JAXP provider [" + factory +
"] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
"Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
pcex.initCause(ex);
throw pcex;
}
}
}
return factory;
}
protected DocumentBuilder createDocumentBuilder(
DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler)
throws ParserConfigurationException {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
if (entityResolver != null) {
docBuilder.setEntityResolver(entityResolver);
}
if (errorHandler != null) {
docBuilder.setErrorHandler(errorHandler);
}
return docBuilder;
}
3、定義一個Document解析器並進行註冊BeanDefintion,
XmlBeanDefinitionReader.doLoadBeanDefinitions裡呼叫的registerBeanDefinitions方法如下
此處BeanDefinitioinDocumentReader使用的是是DefaultBeanDefinitionDocumentReader。不過此處並不是通過new出來一個BeanDefinitionDocumentReader,而是通過BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
4、DefaultBeanDefinitionDocumentReader的registerBeanDefinition方法主要呼叫瞭如下 的doRegisterBeanDefinition方法
通過DefaultBeanDefinitionDocumentReader進行註冊,建立一個BeanDefinitionParserDelegate
protected void doRegisterBeanDefinitions(Element root) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "environment property must not be null");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
// any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createHelper(readerContext, root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
5、其中的parseBeanDefinitions主解析xml的bean的主要解析類,呼叫了BeanDefinitionParserDelegate.parseBeanDefinitionElement解析beanDefinition
BeanDefinitionParserDelegate.parseCustomElement可以根據指定的xml的namesapce自定義xmlbean的解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
DefaultBeanDefinitionDocumentReader.parseDefaultElement方法如下
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
6、解析定義xml檔案的bean.並註冊,解析出來的的beanDefinition封裝到BeanDefinitionHolder中
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
其中呼叫BeanDefinitionParserDelegate.parseBeanDefinitionElement進行xml的bean的解析
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
在解析每個bean時會生成一個beanDefinition的子類,預設生成的是GenerateBeanDefinition,BeanDefinitionParserDelegate.createBeanDefinition方法如下
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
其中的BeanDefinitionReaderUtils.createBeanDefinition方法如下
public static AbstractBeanDefinition createBeanDefinition(
String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
7、註冊beanDefinition
DefaultBeanDefinitionDocumentReader.processBeanDefintion在呼叫BeanDefinitionParserDelegate.parseBeanDefinitionElement方法後得到BeanDefinitionHolder
會對BeanDefinitionHolder進行BeanDefinition的註冊
<pre name="code" class="html">BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
呼叫之前的beanFactory進行beanDefinition的註冊,此處實現註冊的beanFactory是DefaultListableBeanFactory
相關推薦
spring學習(四)xml檔案的BeanDefinition讀取
上一節中說明了spring在讀取bean時主要的方法refresh中,首先要把配置和註解的bean檔案以beanDefintion的形式快取起來,這個方法是refreshBeanFactory() 各類呼叫的程式圖如下 @Override protected fin
spring學習(四)使用註解代替xml配置
用的是IDEA的maven工程,pom.xml檔案導包依賴省略 一、書寫要匯入容器的實體類 import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation
MyBatis學習(四)XML配置文件之SQL映射的XML文件
元素 數據庫 resultmap ash 有一點 oracl 解決 轉換成 插入語 SQL映射文件常用的元素: 1.select 查詢語句是MyBatis最常用的語句之一。 執行簡單查詢的select元素是非常簡單的: <select id=”sele
Spring 學習(五)——XML 配置裡的 Bean 自動裝配
XML 配置裡的 Bean 自動裝配 •Spring IOC 容器可以自動裝配 Bean. 需要做的僅僅是在 <bean> 的 autowire 屬性裡指定自動裝配的模式 •byType(根據型別自動裝配): 若 IOC 容器中有多個與目標 Bean 型別一致的 Bean. 在這
Spring 學習(四)——注入屬性值細節
字面值 •字面值:可用字串表示的值,可以通過 <value> 元素標籤或 value 屬性進行注入。 •基本資料型別及其封裝類、String 等型別都可以採取字面值注入的方式 •若字面值中包含特殊字元,可以使用 <![CDATA[]]> 把字面值包裹起來。 &
Spring學習(四)Jdbc連線池交個spring管理和事務操作
一、連線池的配置交給Spring管理 1,新增jar包 2,spring的jdbc連線池配置 <!-- 配置連線池 --> <bean id="dataSource" class="org.spring
Spring 學習 (四) 註解的使用
分四塊 1.如何將使用註解當前類放入到容器? 將當前類放入Spring容器(如果不新增名稱,則以當前類名為預設名稱) @Component("user")//相當於<bean name="user" class="cn.itcast.bean.U
Spring學習(四)-Bean的三種裝配方式
本篇部落格主要講述Spring中Bean的三種主要裝配:1、在XML中進行顯示配置;2、自動裝配方式;3、在Java中進行顯示配置。下面分別來研究上述三種裝配方式。 在Spring IOC容器中注入依賴資源主要有以下兩種基本實現方式:(1)構造器注入:容器例項
Spring Boot學習(四)
自動配置 pat xml配置 XML 入口 spa ges auto classpath @SpringBootApplication 每一個Spring Boot項目都有一個名為*Application的入口類,入口類中有個main方法,在main方法中使用: Sprin
python學習(四)檔案讀寫
三種模式介紹:#r只讀模式,預設的,未指定模式時為只讀 r 開啟檔案不存在的話,會報錯 ; r+ 讀寫模式 #寫模式 w 會將原來檔案中的內容清空 開啟檔案不存在的話,會新建一個檔案 w+ 寫讀模式,雖然能讀,但是因為把檔案內容清空了,讀到的就是空 #追加模式 a+ 追加讀模式
Maven學習筆記(四)--pom檔案
pom.xml檔案 通過maven構建的專案在根目錄下都會有pom.xml這個檔案 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-i
PE檔案格式學習(四):匯入表
UPDATE: 在文章的末尾更新了一張圖,在網上找的,有助於理解匯入表的結構 1.概述 匯入表是逆向和病毒分析中比較重要的一個表,在分析病毒時幾乎第一時間都要看一下程式的匯入表的內容,判斷程式大概用了哪些功能。 匯入表是資料目錄表中的第2個元素,排在匯出表的
Spring MVC(四)檔案上傳
檔案上傳步驟 1.寫一個檔案上傳的頁面 2.寫一個檔案上傳的控制器 注意: 1.method="post" 2.enctype="multipart/form-data" 3.檔案型別上傳元件 type="file" 4.接收檔案引數需要使用MultipartFile 型別的引數
Spring Boot學習(四):使用@SpringBootTest註解進行單元測試
一、簡介 專案中經常會遇到需要單元測試的情況,那麼SpringBoot如何實現這種需求,使用@SpringBootTest註解可以執行環境,測試後臺程式碼。 二、環境準備 eclipse + maven + Spring Boot 三、程式碼示例 pom.xml
Spring的學習(四):Web中的Spring
Spring通常用來開發Web應用。 SpringMVC的執行過程: 我們可以從以下的圖來分析SpringMVC的的執行過程。 1、客戶端在傳送請求的時候,會呼叫DispatcherServlet,Dispatch是SpringMVC的入口,Dispatche
Spring Boot IoC學習(四)依賴注入DI
四、依賴注入DI 簡介 Bean之間的依賴稱為依賴注入。 例:人穿不同的鞋子去完成不同的活動。比如,人穿籃球鞋去打籃球,穿跑步鞋去跑步鍛鍊,穿皮鞋去上班等等。所以人和鞋子就是依賴關係。 我們用程式碼來展現依賴,定義兩個介面,一個事人類(Person),一個是鞋子
Spring的學習(八)——配置檔案詳解
一、Bean標籤和屬性 bean標籤,是根標籤beans內部必須包含的標籤,它是用於宣告具體的類的物件! 二、bean標籤使用 ①name屬性:name不能重複,name可以指定多個,逗號隔開。可以使用特殊字元,也可以根據name屬性獲取一個物件 ②id屬性:
JavaWeb學習筆記 (二)xml檔案的解析
1.xml解析 就是獲取xml檔案中元素的屬性或資料。 2.xml常用的解析方式 (1)DOM解析(document object model):會將xml檔案中的內容全部讀出,在記憶體中以樹狀形式儲存。整個文件稱為document物件,屬性稱為attribute物件,元素節點稱為ele
Spring 學習(八)——使用外部屬性檔案
•在配置檔案裡配置 Bean 時, 有時需要在 Bean 的配置裡混入系統部署的細節資訊(例如: 檔案路徑, 資料來源配置資訊等). 而這些部署細節實際上需要和 Bean 配置相分離 •Spring 提供了一個 PropertyPlaceholderConfigurer 的 BeanFactor
Maven學習(一)配置檔案pom.xml
Maven pom.xml 1、定義: POM全稱專案物件模型(Project Object Model)的簡稱,它是Maven專案中的檔案,使用XML表示,名稱叫做pom.xml。不過這個檔案中包含了該專案所有相關資訊(專案唯一ID、專案依賴、專案url、專案開發者等一切相關資訊)