【Spring】IOC核心源码学习(三):bean标签和自定义标签实现原理
基于schema的spring xml namespace扩展
基于Spring可扩展Schema提供自定义配置,扩展XML配置大致需要一下几个步骤:
1、创建一个需要扩展的组件
2、定义一个xsd文件描述组件内容
3、实现BeanDefinitionParser接口,用来解析xsd文件中的定义和组件定义
4、扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器
5、编写spring.handlers和spring.schemas文件
<!--EndFragment-->
基于Spring可扩展Schema提供自定义配置 扩展XML配置大致需要一下几个步骤, 并将产生的文件打成jar包, 在项目中引用该jar包: 1、创建一个需要扩展的组件 2、定义一个xsd文件描述组件内容 3、实现BeanDefinitionParser接口,用来解析xsd文件中的定义和组件定义 4、扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器 5、编写spring.handlers和spring.schemas文件
注意:spring.handlers和spring.schemas文件, 还有mytag.xsd文件都要放到resources文件夹下, 因为使用maven打包, 所在静态文件必须放在这个文件夹下, 就因为这个问题, 我浪费了一下午的时间, 总是提示找不到mytag.xsd文件
源码大概执行过程:
1、判断标签的命名空间, 是否是默认的命名空间http://www.springframework.org/schema/beans
2、不是默认的命名空间, 则使用自定义标签转换器转换
BeanDefinitionParserDelegate.parseCustomElement(ele)
3、
String namespaceUri = ele.getNamespaceURI(); 通过元素获取命名空间
//取得命名空间解析器DefaultNamespaceHandlerResolver, 找到解析命名空间为namespaceUri的解析器
//取得
NamesresolvepaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
4、加载包下的META-INF/spring.handlers:DefaultNamespaceHandlerResolver.getHandlerMappings()
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;
}
5、从META-INF/spring.handlers中获取对应命名空间的处理类
http\://www.360buy.com/schema/ice=com.jd.common.ice.IceNamespaceHandler
6、加载处理类, 并实例化, 执行处理类的init方法,
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
7、执行处理类的init方法, 将自定义标签解析器注册到NamespaceHandlerSupport.parsers(Map)的属性中
registerBeanDefinitionParser("config", new IceProxyBeanDefinitionParser());
8、执行NamespaceHandlerSupport.parse()方法, 从NamespaceHandlerSupport.parsers的属性中, 找到对应的解析器,执行parse()方法,最终返回BeanDefinition对象,
在parse()方法中, 重要的是:
def.setBeanClass(TagOne.class); 在这里指定生成Bean对象对应的Class
9、何时执行getObject()