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.mzph.cn/news/249601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

github中的watch、star、fork的作用

在每个 github 项目的右上角&#xff0c;都有三个按钮,分别是 watch、star、fork&#xff0c;但是有些刚开始使用 github 的同学&#xff0c;可能对这三个按钮的使用却不怎么了解&#xff0c;包括一开始使用 github 的我也是如此&#xff0c;这篇博客&#xff0c;结合自己的理解…

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;紫…

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 题意:用最小的花费买到刚好合适的东西.我们可…

java项目中的classpath

在java项目中&#xff0c;你一定碰到过classpath&#xff0c;通常情况下&#xff0c;我们是用它来指定配置/资源文件的路径。在刚开始学习的时候&#xff0c;自己也糊里糊涂&#xff0c;但是现在&#xff0c;是时候弄清楚它到底是指什么了。 顾名思义&#xff0c;classpath就是…

Class.getResource和ClassLoader.getResource

一案例驱动 二源码分析 三类加载器ClassLoader 四总结 五参考 一案例驱动 最近加载文件的时候遇到了一个问题&#xff0c;很有意思&#xff01; 具体看下面案例代码 public class TestClassLoader {public static void main(String[] args) {System.out.println(TestClassLoad…

spring-6、动态代理(cglib 与 JDK)

JDK动态代理与Cglib动态代理 JDK动态代理: 1.能够继承静态代理的全部优点.并且能够实现代码的复用.2.动态代理可以处理一类业务.只要满足条件 都可以通过代理对象进行处理.3.动态代理的灵活性不强.4.JDK 的动态代理要求代理者必须实现接口, , 否则不能生成代理对象. . 1 packag…

JDK安装与配置(Windows 7系统)

1.前言 安装之前需弄清JDK、JRE、JVM这几个概念&#xff0c;不然稀里糊涂不知道自己在装什么。 &#xff08;1&#xff09;什么是java环境&#xff1a;我们知道&#xff0c;想听音乐就要安装音乐播放器&#xff0c;想看图片需要安装图片浏览器&#xff0c;同样道理&#xff0c;…

spring源码分析-core.io包里面的类

前些日子看《深入理解javaweb开发》时&#xff0c;看到第一章java的io流&#xff0c;发觉自己对io流真的不是很熟悉。然后看了下JDK1.7中io包的一点点代码&#xff0c;又看了org.springframework.core.io包的一些类和组织方式&#xff0c;当作是学习吧。总结一下。 先挂下spri…

对类Vue的MVVM前端库的实现

关于实现MVVM&#xff0c;网上实在是太多了&#xff0c;本文为个人总结&#xff0c;结合源码以及一些别人的实现 关于双向绑定 vue 数据劫持 订阅 - 发布ng 脏值检查backbone.js 订阅-发布(这个没有使用过&#xff0c;并不是主流的用法)双向绑定&#xff0c;从最基本的实现来说…

django的母板系统

一.母板渲染语法 1.变量 {{ 变量 }} 2.逻辑 {% 逻辑语 %} 二.变量 在母板中有变量时,母板引擎会去反向解析找到这个传来的变量,然后替换掉. .(点),在母板中是深度查询据点符,它的查询顺序: 字典 > 属性或方法 > 数字索引 三.过滤器 1.语法 {{ value|filter_name:参数}} 2…