问题
Note: the test project I'm mentioning can be downloaded with:
git clone https://github.com/mperdikeas/so-spring-di-appcontext-schemalocation.git
.. and run with 'ant run'.
I 'understand' that XML namespace names are just used as opaque identifiers and not meant to be used as URIs (wikipedia). I also 'understand' that the XML schema locations are meant to provide hints as to the actual location of schema documents and, being hints, not used in practice (w3.org). With that in mind I 've been experimenting with a simple Spring DI application (used in a simple J2SE setting) by modifying the applicationContext.xml. Here is the starting version:
<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:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="atm"/>
<context:property-placeholder location="classpath:META-INF/spring/atm.properties"/>
<bean id="soapTransport_" class="atm.SoapATMTransport" p:retries="${transport.retries}"/>
When I did a 'sudo ifconfig eth0 down' the project ran perfectly which is consistent with the runtime not bothering to fetch anything from the schemaLocations. However, when I mangled the schemaLocations by adding a simple underscore to the second URL in each pair I received the following complaint:
[java] org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 10 in XML document from class path resource [META-INF/spring/applicationContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 10; columnNumber: 100; cvc-elt.1: Cannot find the declaration of element 'beans'.
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:194)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:771)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:221)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
[java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:108)
[java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[java] at java.lang.reflect.Method.invoke(Method.java:601)
[java] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[java] at org.apache.tools.ant.Task.perform(Task.java:348)
[java] at org.apache.tools.ant.Target.execute(Target.java:390)
[java] at org.apache.tools.ant.Target.performTasks(Target.java:411)
[java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
[java] at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
[java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[java] at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:809)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:217)
[java] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
[java] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
Which seems to suggest that Spring DI runtime uses the second URL in each pair at the xsi:schemaLocation as some kind of identifier (hardcoded in its logic since there is no network access). So my assumption would be that the Spring DI runtime uses two kind of identifiers for each namespace: the xmlns identifier to uniquely identify the namespace (used as an opaque string) and the schemaLocation identifier to uniquely identify the schema version for that namespace (again used as an opaque string). I.e. the schemaLocation is actually used (in a contorted way ? as that doesn't seem to be the intention of the w3c documents) to version the namespace. Moreover, in such a case, why doesn't the Spring DI runtime complain about the lack of a schemaLocation for the "p" namespace. Is my mental model correct?
回答1:
Here is what happens:
XML schema allows you to define aliases (short names) to XML namespaces. Technically all namespaces are identified by full URI but that would be very cumbersome - so you can use short aliases like
context
andp
. There is also a default namespace denoted byxmlns
attributeBy default XML parsers assume namespace URI is also a XSD file URL location. This is often the case, but is not required by the spec. This is also how XML parser in Spring works if you don't provide
schemaLocation
attribute.schemaLocation
is used to map from namespace URI to XSD file physical location (URL). It is used when schema namespace does not point to valid XSD URL (see MSDN on schemaLocation).Last but not least, Spring adds yet another layer that translates Internet URLs to local files on CLASSPATH. This way your application can start without Internet connection (or when springframework.org site is down).
If you search your project libraries you'll find several files named spring.schemas
. These files contain lines similar to below (extract from the file found in spring-context.jar
, I added alignment):
http\://www.springframework.org/schema/context/spring-context.xsd= org/springframework/context/config/spring-context-3.1.xsd
http\://www.springframework.org/schema/jee/spring-jee.xsd= org/springframework/ejb/config/spring-jee-3.1.xsd
http\://www.springframework.org/schema/lang/spring-lang.xsd= org/springframework/scripting/config/spring-lang-3.1.xsd
http\://www.springframework.org/schema/cache/spring-cache.xsd= org/springframework/cache/config/spring-cache-3.1.xsd
来源:https://stackoverflow.com/questions/10768873/spring-di-applicationcontext-xml-how-exactly-is-xsischemalocation-used