springxml解析

1.XML驗證模式的認識
首先XML的驗證模式有兩種:DTD和XSD。

DTD文檔類型定義,是XML約束模式語言。它是為了保證XML文檔格式正確有效的方法。通過XML文檔和DTD文檔的比較來判斷XML是否符合規范。(現在我很少見,不知道是不是淘汰了)

舉個例子:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD BEAN 2.0//EN""http://www.Springframework.org/dtd/Spring-beans-2.0.dtd">
<beans>
...   
</beans>

XSD(XML Schemas Definition),它描述了XML文檔的結構和規范,可以指定一個XML文檔允許的結構和內容,通過這樣就可以校驗某一個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"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd">

上面的http://www.springframework.org/schema/beans/spring-beans.xsd,這個命名空間,就指定了xml中bean的驗證方式。 具體的校驗我就不介紹了,每一個命名空間都可以查看對應的校驗內容 。

2.通過ClassPathXmlApplicationContext來認識spring
下面以我們剛接觸spring時,通過ClassPathXmlApplicationContext獲取bean的方式來認識spring源碼。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><bean id="user" class="support.mode.User"><property name="useId" value="00232"></property><property name="userName" value="topsnowwolf"/></bean></beans>
public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-mvc.xml");User user = applicationContext.getBean(User.class);System.out.println(user.getUseId()+":"+user.getUserName());}

認識前先了解類,接口的關系:
在這里插入圖片描述
現在我們初步認識一下下面這幾個對象:

BeanFactory:定義獲取bean以及bean的各種屬性。
ListableBeanFactory:根據各種條件獲取bean的配置清單。
ResourceLoader:資源加載器
AbstractApplicationContext:這個抽象類的refresh方法為是解析xml,獲取,加載bean的入口。
在實例化ClassPathXmlApplicationContext對象時,會調用ClassPathXmlApplicationContext的構造方法創建對象,在創建

ClassPathXmlApplicationContext時,就會進行一系列的操作。

經過分析入口就是AbstractApplicationContext類的refresh方法。

public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//獲取BeanFactory配置清單this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

ConfigurableListableBeanFactory對象的創建。

ConfigurableListableBeanFactory:是BeanFactory配置清單。

ConfigurableListableBeanFactory和DefaultListableBeanFactory的關系圖。
在這里插入圖片描述
獲取BeanFactory配置清單

通過obtainFreshBeanFactory()方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();//獲取DefaultListableBeanFactory對象。ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();if (this.logger.isDebugEnabled()) {this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);}return beanFactory;}

refreshBeanFactory方法的認識: 由于AbstractApplicationContext類的refreshBeanFactory方法是抽象方法,實現類是AbstractRefreshableApplicationContext。

關系圖:

在這里插入圖片描述

protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
protected final void refreshBeanFactory() throws BeansException {if (this.hasBeanFactory()) {this.destroyBeans();this.closeBeanFactory();}try {DefaultListableBeanFactory beanFactory = this.createBeanFactory();beanFactory.setSerializationId(this.getId());//給DefaultListableBeanFactory設置序列化IDthis.customizeBeanFactory(beanFactory);//當我們配置了兩個name屬性相同的Bean時,spring默認會后面配置的Bean會覆蓋掉前面配置的Bean對象this.loadBeanDefinitions(beanFactory);//Object var2 = this.beanFactoryMonitor;synchronized(this.beanFactoryMonitor) {this.beanFactory = beanFactory;}} catch (IOException var5) {throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);}}
AbstractRefreshableApplicationContext的方法loadBeanDefinitions實現由AbstractXmlApplicationContext。

關系圖:

在這里插入圖片描述

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));this.initBeanDefinitionReader(beanDefinitionReader);this.loadBeanDefinitions(beanDefinitionReader);}

最后loadBeanDefinitions這方法繞來繞去,會調用到XmlBeanDefinitionReader中的loadBeanDefinitions方法。 到現在還沒真正的解析XML,之前的工作全部是準備。是不是很繞啊。

3.Spring解析XML成document的過程
XmlBeanDefinitionReader類中的loadBeanDefinitions就是重點了!!!

大概思路:

xml等配置會被注冊到容器中,xml文件最終都會通過ResourceLoader加重成Resource對象,通Reader進行解析讀取,最后注冊到容器中,spring以sax的方式解析xml。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");if (this.logger.isInfoEnabled()) {this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());}Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();if (currentResources == null) {currentResources = new HashSet(4);this.resourcesCurrentlyBeingLoaded.set(currentResources);}if (!((Set)currentResources).add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");} else {int var5;try {InputStream inputStream = encodedResource.getResource().getInputStream();try {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());} finally {inputStream.close();}} catch (IOException var15) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);} finally {((Set)currentResources).remove(encodedResource);if (((Set)currentResources).isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}return var5;}}

第一步:

XmlBeanDefinitionReader類的loadBeanDefinitions(Resource resource)方法將Resource對象封裝成EncodedResource對象。(EncodedResource的作用是對資源文件進行編碼格式處理,處理方法看EncodedResource類的getReader())

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return this.loadBeanDefinitions(new EncodedResource(resource));}
public class EncodedResource implements InputStreamSource {private final Resource resource;private final String encoding;private final Charset charset;public EncodedResource(Resource resource) {this(resource, (String)null, (Charset)null);}public EncodedResource(Resource resource, String encoding) {this(resource, encoding, (Charset)null);}public EncodedResource(Resource resource, Charset charset) {this(resource, (String)null, charset);}private EncodedResource(Resource resource, String encoding, Charset charset) {Assert.notNull(resource, "Resource must not be null");this.resource = resource;this.encoding = encoding;this.charset = charset;}
....

第二步:

從EncodedResource中獲取InputStream ,之后將InputStream 轉化為InputSource。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");if (this.logger.isInfoEnabled()) {this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());}Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();//通過屬性來記錄已經加載的資源。if (currentResources == null) {currentResources = new HashSet(4);this.resourcesCurrentlyBeingLoaded.set(currentResources);}if (!((Set)currentResources).add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");} else {int var5;try {InputStream inputStream = encodedResource.getResource().getInputStream();//從EncodedResource中獲取InputStream 。try {InputSource inputSource = new InputSource(inputStream);//將InputStream 轉化為InputSource?為何要轉化為InputSource呢?下面解析xml時再解釋。if (encodedResource.getEncoding() != null) {//設置編碼格式inputSource.setEncoding(encodedResource.getEncoding());//}var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());//進入解析XML的核心代碼} finally {inputStream.close();}} catch (IOException var15) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);} finally {((Set)currentResources).remove(encodedResource);if (((Set)currentResources).isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}return var5;}}

第三步:

進入解析XML(小知識 xml的解析方式:jdk的提供的dom解析,dom4j,sax常用的三種。)

由于spring對xml的解釋是采用sax方式進行解析的,所以現在大概知道為什么要將InputStream 轉化為InputSource了吧。因為sax解析xml時,parse方法入參就必須是sax提供的InputSource流對象。

this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());//進入解析XML的核心代碼
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {try {Document doc = this.doLoadDocument(inputSource, resource);//sax方式解釋xmlreturn this.registerBeanDefinitions(doc, resource);//注冊bean} catch (BeanDefinitionStoreException var4) {throw var4;} catch (SAXParseException var5) {throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);} catch (SAXException var6) {throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);} catch (ParserConfigurationException var7) {throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);} catch (IOException var8) {throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);} catch (Throwable var9) {throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);}}

初略說一下:doLoadDocument

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), //向SAX 驅動器注冊一個實例EntityResolver,至于為何要一定要這個EntityResolver這個實例給SAX,就不多說了。this.errorHandler, //SimpleSaxErrorHandler對象this.getValidationModeForResource(resource), //XML驗證方式的讀取this.isNamespaceAware()  //);}
protected int getValidationModeForResource(Resource resource) {int validationModeToUse = this.getValidationMode();if (validationModeToUse != VALIDATION_AUTO) {//如果手動指定了驗證模式則使用指定的驗證模式return validationModeToUse;} else {//沒有自動檢測int detectedMode = this.detectValidationMode(resource);return detectedMode != VALIDATION_AUTO ? detectedMode : VALIDATION_XSD;}}

調用DefaultDocumentLoader類中的loadDocument解析xml

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);//創建一個工廠(工廠模式)if (logger.isDebugEnabled()) {logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");}DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);//獲取建造者(建造者模式)return builder.parse(inputSource);//解釋XML成Document}

sax如何解析xml成Document這里就不廢話了。

第四步:

將解析的document對應的bean注冊到spring容器中。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();//實例化BeanDefinitionDocumentReaderint countBefore = this.getRegistry().getBeanDefinitionCount();//總結已經存在的BeanDefinition個數documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));//加載注冊bean  核心return this.getRegistry().getBeanDefinitionCount() - countBefore;//返回本次加載的BeanDefinition個數}

這里就是最最最核心的代碼了。
BeanDefinitionDocumentReader是一個接口,而實例化由createBeanDefinitionDocumentReader()完成!

 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));}

通過這個可以知道,BeanDefinitionDocumentReader的實現類是DefaultBeanDefinitionDocumentReader。 下面我們重點看一下DefaultBeanDefinitionDocumentReader類中的registerBeanDefinitions()方法。

 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;this.logger.debug("Loading bean definitions");Element root = doc.getDocumentElement();//獲取document的元素。this.doRegisterBeanDefinitions(root);}

此時我們才真真正正的看到了底層的實現方法。繞來繞去,終于看到了曙光!!!下面我們接著分析doRegisterBeanDefinitions(root)方法。

protected void doRegisterBeanDefinitions(Element root) {BeanDefinitionParserDelegate parent = this.delegate;this.delegate = this.createDelegate(this.getReaderContext(), root, parent);//實例化BeanDefinitionParserDelegate,是一個解析器代理類。if (this.delegate.isDefaultNamespace(root)) {String profileSpec = root.getAttribute("profile");//處理profile屬性,profile來實現動態生成相應的bean,如何實現網上很多例子,這里就不介紹了。https://www.cnblogs.com/yw0219/p/5990056.html,https://www.jianshu.com/p/948c303b2253這兩篇文章介紹得很具體。if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {return;}}}this.preProcessXml(root);this.parseBeanDefinitions(root, this.delegate);this.postProcessXml(root);this.delegate = parent;}

此時會發現,這里才是真真正正對XML的每一個節點進行解析! 大略看一下BeanDefinitionParserDelegate的,你發現它實際就是封裝了bean的各種屬性。

public class BeanDefinitionParserDelegate {public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";public static final String TRUE_VALUE = "true";public static final String FALSE_VALUE = "false";public static final String DEFAULT_VALUE = "default";public static final String DESCRIPTION_ELEMENT = "description";public static final String AUTOWIRE_NO_VALUE = "no";public static final String AUTOWIRE_BY_NAME_VALUE = "byName";public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";public static final String NAME_ATTRIBUTE = "name";public static final String BEAN_ELEMENT = "bean";public static final String META_ELEMENT = "meta";public static final String ID_ATTRIBUTE = "id";public static final String PARENT_ATTRIBUTE = "parent";public static final String CLASS_ATTRIBUTE = "class";public static final String ABSTRACT_ATTRIBUTE = "abstract";public static final String SCOPE_ATTRIBUTE = "scope";private static final String SINGLETON_ATTRIBUTE = "singleton";public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";public static final String AUTOWIRE_ATTRIBUTE = "autowire";public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";public static final String PRIMARY_ATTRIBUTE = "primary";public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";public static final String INIT_METHOD_ATTRIBUTE = "init-method";public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";public static final String INDEX_ATTRIBUTE = "index";public static final String TYPE_ATTRIBUTE = "type";public static final String VALUE_TYPE_ATTRIBUTE = "value-type";public static final String KEY_TYPE_ATTRIBUTE = "key-type";public static final String PROPERTY_ELEMENT = "property";public static final String REF_ATTRIBUTE = "ref";public static final String VALUE_ATTRIBUTE = "value";public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";public static final String REPLACED_METHOD_ELEMENT = "replaced-method";public static final String REPLACER_ATTRIBUTE = "replacer";public static final String ARG_TYPE_ELEMENT = "arg-type";public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";public static final String REF_ELEMENT = "ref";public static final String IDREF_ELEMENT = "idref";public static final String BEAN_REF_ATTRIBUTE = "bean";public static final String LOCAL_REF_ATTRIBUTE = "local";public static final String PARENT_REF_ATTRIBUTE = "parent";public static final String VALUE_ELEMENT = "value";public static final String NULL_ELEMENT = "null";public static final String ARRAY_ELEMENT = "array";public static final String LIST_ELEMENT = "list";public static final String SET_ELEMENT = "set";public static final String MAP_ELEMENT = "map";public static final String ENTRY_ELEMENT = "entry";public static final String KEY_ELEMENT = "key";public static final String KEY_ATTRIBUTE = "key";public static final String KEY_REF_ATTRIBUTE = "key-ref";public static final String VALUE_REF_ATTRIBUTE = "value-ref";public static final String PROPS_ELEMENT = "props";public static final String PROP_ELEMENT = "prop";public static final String MERGE_ATTRIBUTE = "merge";public static final String QUALIFIER_ELEMENT = "qualifier";public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute";public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates";public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";protected final Log logger = LogFactory.getLog(this.getClass());private final XmlReaderContext readerContext;private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();private final ParseState parseState = new ParseState();private final Set<String> usedNames = new HashSet();......

parseBeanDefinitions()這個方法必須重點認識!!!

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)) {this.parseDefaultElement(ele, delegate);//解析默認的bean} else {delegate.parseCustomElement(ele);//解析自定義的bean}}}} else {delegate.parseCustomElement(root);}}

不同bean的認識:

默認的bean:

<bean id="user" class="support.mode.User"><property name="useId" value="00232"></property><property name="userName" value="topsnowwolf"/></bean>

自定義的bean:

<tx:annotation-driven />

這兩者區別很大,如果是spring默認配置的bean,spring肯定知道如何處理,自定義的就要實現一下接口和配置。 問題spring是如何知道是默認的還是自定義的呢?

public boolean isDefaultNamespace(String namespaceUri) {return !StringUtils.hasLength(namespaceUri) || "http://www.springframework.org/schema/beans".equals(namespaceUri);}public boolean isDefaultNamespace(Node node) {return this.isDefaultNamespace(this.getNamespaceURI(node));}

判斷是默認的還是自定義的,通過標簽對應的命名空間去判斷。

當命名空間是http://www.springframework.org/schema/beans時,就是默認的。下次我將總結一下如何自定義spring的標簽,這樣就能更好的認識自定義的解析,這里就不多說了。不過為了有點了解還是舉個例子吧。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 自動掃描 --><context:component-scan base-package="support.*"/><tx:annotation-driven /><!-- 第一種方式:加載一個properties文件 --><bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location" value="classpath:jdbc.properties"/></bean>

上面這一部分配置:

我們可以看到 context標簽對應的命名空間就是http://www.springframework.org/schema/context。

tx的是http://www.springframework.org/schema/tx。

差不多了!!!

最后總結一下整個過程:
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249601.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249601.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249601.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

jq函數綁定與解綁

最近學到幾個新的jq函數 1、bind&#xff08;&#xff09;綁定函數 2、unbind&#xff08;&#xff09;解綁函數 3、add() .給元素追加字符串 4、addClass() 給某元素增加class屬性值轉載于:https://www.cnblogs.com/bigwang1126/p/9566556.html

微信小程序時間標簽與范圍聯動設計實現

微信小程序時間標簽與范圍聯動設計實現&#xff1f;最近忙于一個有關數據管理的微信小程序開發&#xff0c;遇到了上圖情況&#xff0c;雖然很簡單&#xff0c;還是整理一下。若有錯誤&#xff0c;請廣大朋友們指正。 使用微信小程序組件radio-group、picker&#xff0c;用wxss…

github中的watch、star、fork的作用

在每個 github 項目的右上角&#xff0c;都有三個按鈕,分別是 watch、star、fork&#xff0c;但是有些剛開始使用 github 的同學&#xff0c;可能對這三個按鈕的使用卻不怎么了解&#xff0c;包括一開始使用 github 的我也是如此&#xff0c;這篇博客&#xff0c;結合自己的理解…

docker 操作 記錄

docker ps #查看當前docker容器 docker exec -it 容器名稱 sh 進入docker容器 docker stop 停止docker容器轉載于:https://www.cnblogs.com/objects/p/9569299.html

關于群論證明費馬小定理?

這篇博客就是講證費馬的&#xff0c;沒什么意思。 既然是要用群論證明費馬小定理&#xff0c;那么我們先用數論證明一下。 (以下的 p 為一個質數) 首先我們考慮 一個前置定理&#xff1a; 第一個證明 若 $(c,p) 1$ (即 c 與 p 的 gcd 為 1)&#xff0c;且 $ac ≡ bc (mod\ p)$ …

spring 源碼-context

1 spring-context 模塊概要 該模塊主要實現在spring-beans 模塊的擴展&#xff0c;主要對aop支持及el表達式的實現 分析示例 public static void main(String[] args){ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext("spring-aop.xml"…

標示符和關鍵字的總結--希望別再犯錯

&#xff08;一&#xff09;Java關鍵字的表 一共50個關鍵字&#xff0c;如下表 其中絕大部分關鍵詞是Java語法發布之初就約定好的&#xff0c;少部分關鍵詞是隨Java語言發展后加入的。 strictfp JDK1.2 加入 assert JDK1.4 加入 enum JDK5.0 加入 還有少數單詞&#xff0c;目前…

歷屆試題 打印十字圖

問題描述 小明為某機構設計了一個十字型的徽標&#xff08;并非紅十字會啊&#xff09;&#xff0c;如下所示&#xff1a; ..$$$$$$$$$$$$$....$...........$..$$$.$$$$$$$$$.$$$$...$.......$...$$.$$$.$$$$$.$$$.$$.$...$...$...$.$$.$.$$$.$.$$$.$.$$.$.$...$...$.$.$$.$.$.…

Spring BeanDefinition

BeanDefinition&#xff0c;顧名思義&#xff0c;是一個對象(Bean)在Spring中描述&#xff0c;其核心類圖&#xff1a; 從類圖我們詳細了解BeanDefinition。 BeanDefinition接口繼承自BeanMetadataElement和AttributeAccessor兩個接口。 BeanMetadataElement&#xff1a;bean…

樂尚網絡:小程序商城零售行業10大新賦能

微信小程序上線以來&#xff0c;各行各業積極入場小程序&#xff0c;著手打造屬于自己的小程序生態。小程序形態多樣&#xff0c;適合你的小程序才是最好的&#xff1b;在眾多形態中&#xff0c;小程序商城可以說是零售行業的主體形態了&#xff0c;因為通過平臺直接實現交易是…

深度學習中的正則化

正則化方法有如下幾種&#xff1a; 一、參數范數懲罰 其中L2、L1參數正則化介紹與關系如下 1、L2 參數正則化 直觀解釋如下&#xff1a; 2、L1 參數正則化 二、獲取更多數據&#xff08;擴樣本&#xff09; 避免過擬合的基本方法之一是從數據源獲得更多數據&#xff0c;當訓練數…

spring uml

spring執行流程&#xff1a; 1&#xff1a; 加載spring.xml文件 2&#xff1a; 創建xml文件解析器 3&#xff1a; 獲取命名空間&#xff0c;即在spring.xml文件中的 http://www.springframework.org/schema/context 4&#xff1a; 根據命名空間找到命名空間處理器&#xff0c;在…

「造個輪子」——cicada(輕量級 WEB 框架)

前言 俗話說 「不要重復造輪子」&#xff0c;關于是否有必要不再本次討論范圍。 創建這個項目的主要目的還是提升自己&#xff0c;看看和知名類開源項目的差距以及學習優秀的開源方式。 好了&#xff0c;現在著重來談談 cicada 這個項目的核心功能。 我把他定義為一個快速、輕量…

基于owncloud構建私有云儲存網盤

注意事項&#xff1a;需要ping通外網 需要LAMP架構yum -y install httpd php php-mysql mariadb-server mariadb sqlite php-dom php-mbstring php-gd php-pdo 開啟服務[rootowncloud ~]# setenforce 0setenforce: SELinux is disabled[rootowncloud ~]# systemctl stop firewa…

Spring 源碼分析之AbstractApplicationContext源碼分析

首先我覺得分析ApplicationContext必須從它的實現類開始進行分析&#xff0c;AbstractApplicationContext我覺得是一個不錯的選擇&#xff0c;那我們就從這里開始逐一分析吧&#xff0c;首先我自己手畫了一張圖&#xff0c;作為索引吧&#xff0c;其中藍色的為類&#xff0c;紫…

[USACO15FEB]Superbull (最小生成樹)

題目鏈接 Solution 基本上就是個板子. 因為 \(n\) 很小,只有 \(2000\),所以直接暴力建圖,然后跑最小生成樹就好了. Code #include<bits/stdc.h> #define ll long long using namespace std; const int maxn2008; struct sj{int to,fr; ll w; }a[maxn*maxn]; int fa[maxn]…

Java中九大內置對象

1、Request對象 該對象封裝了用戶提交的信息&#xff0c;通過調用該對象相應的方法可以獲取封裝的信息&#xff0c;即使用該對象可以獲取用戶提交的信息。 當Request對象獲取客戶提交的漢字字符時&#xff0c;會出現亂碼問題&#xff0c;必須進行特殊處理。首先&#xff0c;…

ORACLE導出導入意外終止導致 ORACLE initialization or shutdown in progress 問題解決

由于意外情況導致 ORACLE initialization or shutdown in progress 個人理解為主要是歸檔日志出現問題&#xff0c; 首先cmd 1.sqlplus /nolog 進入sqlplus 2.connect /as sysdba 連接dba 3.shutdown normal 卸載數據庫 4.startup mount;重啟例程 5.alter database open;開…

Spring中資源的加載ResourceLoader

Spring中資源的加載是定義在ResourceLoader接口中的&#xff0c;它跟前面提到的抽象資源的關系如下&#xff1a; ResourceLoader的源碼 public interface ResourceLoader { /** Pseudo URL prefix for loading from the class path: "classpath:" */ String CLAS…

Codeforces Round #540 (Div. 3)(部分題解)

鏈接:http://codeforces.com/contest/1118 來源:Codeforces 文章目錄A. Water BuyingB. Tanya and Candies(前綴和)D1. Coffee and Coursework (Easy version)(貪心)D2. Coffee and Coursework (Hard Version)(二分)A. Water Buying 題意:用最小的花費買到剛好合適的東西.我們可…