'*.xsd' is necessary for describing the rules of spring xml context construction. E.g. the following simple spring xml config snippet defines three spring schemas - 'beans', 'aop' and 'context':
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="com.spring.example.aop"/>
<bean id="methodInterceptor" class="com.spring.example.aop.AopMethodInterceptor"/>
<bean id="pojoAspect" class="com.spring.example.aop.PojoAspect"/>
<aop:config>
<aop:advisor advice-ref="methodInterceptor" pointcut="execution(* com.spring.example.aop.AopService.*(..))"/>
</aop:config>
<aop:config>
<aop:aspect ref="pojoAspect">
<aop:before method="pojoAdvice" pointcut="execution(* com.spring.example.aop.AopService.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
Let's see what happens when we instantiate spring context with such config:
- Spring shoud parse the '*.xml';
- Spring defines custom EntityResolver for the xml parser - DelegatingEntityResolver;
- 'DelegatingEntityResolver.resolveEntity()' calls PluggableSchemaResolver.resolveEntity();
- 'PluggableSchemaResolver.resolveEntity()' calls 'PluggableSchemaResolver.getSchemaMappings()';
- 'PluggableSchemaResolver.getSchemaMappings()' tries to load properties from all resources named 'META-INF/spring.schemas' ('PluggableSchemaResolver.DEFAULT_SCHEMA_MAPPINGS_LOCATION') found at classpath during calling to PropertiesLoaderUtils.loadAllProperties();
- 'PluggableSchemaResolver.resolveEntity()' tries to resolve target shema against classpath using the data from loaded properties;
- And here is a 'PropertiesLoaderUtils.loadAllProperties()' code:
public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
Assert.notNull(resourceName, "Resource name must not be null");
ClassLoader clToUse = classLoader;
if (clToUse == null) {
clToUse = ClassUtils.getDefaultClassLoader();
}
Properties properties = new Properties();
Enumeration urls = clToUse.getResources(resourceName);
while (urls.hasMoreElements()) {
URL url = (URL) urls.nextElement();
InputStream is = null;
try {
URLConnection con = url.openConnection();
con.setUseCaches(false);
is = con.getInputStream();
properties.load(is);
}
finally {
if (is != null) {
is.close();
}
}
}
return properties;
}
Let's check the processing one more time on 'beans' schema example:
- Our xml config defines 'beans' schema location as 'http://www.springframework.org/schema/beans/spring-beans-3.0.xsd';
- All contents of classpath resources named 'META-INF/spring.schemas' are loaded;
- There is 'META-INF/spring.schemas' file at 'spring-beans.jar', it contains property 'http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd' among the others;
- 'PluggableSchemaResolver' tries to load schema data from classpath resource defines as a target property value ('org/springframework/beans/factory/xml/spring-beans-3.0.xsd');
- You can see that there is 'org/springframework/beans/factory/xml/spring-beans-3.0.xsd' resource inside 'spring-beans.jar'. It's loaded and returned as a resolved xml entity;
That's it - target '*.xsd' file is loaded from classpath. Spring tries to load it from the web if it can't be loaded from classpath.
Note: spring uses the same technique for loading namespace handlers necessary for correct context instantiation - see DefaultNamespaceHandlerResolver. That's the reason why you should define custom schema definition and handler at 'META-INF/spring.schemas' and 'META-INF/spring.handlers' files as described at the reference.

Very helpful article. Thanks.
ReplyDeleteWelcome
ReplyDeleteThanks for the article. This helped me debug a library I was using which was having a problem with schema location resolution.
ReplyDeleteWelcome :)
ReplyDeleteI was at the same situation - schema location resolution was incorrect, hence, I spent time to checking spring processing on that and just shared the knowledge