spring原始碼(9)自定義標籤與自定義標籤的解析
阿新 • • 發佈:2019-01-23
一、自定義標籤
- 建立model
package com.demo3;
/**
*
* @author dqf
* @since 5.0
*/
public class User {
private String userName;
private String email;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
- 定義一個XSD檔案描述
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.dqf.com/schema/user"
xmlns:tns="http://www.dqf.com/schema/user" elementFormDefault="qualified">
<element name="user">
<complexType>
<attribute name="id" type="string"></attribute>
<attribute name="userName" type="string"></attribute>
<attribute name="email" type="string"> </attribute>
</complexType>
</element>
</schema>
- 定義用來解析XSD檔案中定義和元件
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser{
protected Class getBeanClass(Element element){
return User.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder bean) {
String userName = element.getAttribute("userName");
String email = element.getAttribute("email");
if(org.springframework.util.StringUtils.hasText(userName)){
bean.addPropertyValue("userName", userName);
}
if(org.springframework.util.StringUtils.hasText(email)){
bean.addPropertyValue("email", email);
}
}
}
- 定義一個Handler檔案,將元件註冊到Spring容器
public class MyNamespaceHandler extends NamespaceHandlerSupport{
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}
- 新增Spring.handlers,spring.schemas檔案
http\://www.dqf.com/schema/user=com.demo3.MyNamespaceHandler
http\://www.dqf.com/schema/user.xsd=META-INF/customtag.xsd
- 測試
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:myname="http://www.dqf.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.dqf.com/schema/user
http://www.dqf.com/schema/user.xsd">
<myname:user id="testbean" userName="aaa" email="bbb"></myname:user>
<bean id="myTestBean" class="com.demo.model.MyTestBean" />
</beans>
public class App {
public static void main(String[] args) {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("springContext.xml"));
MyTestBean testBean = (MyTestBean)bf.getBean("myTestBean");
System.out.println(testBean.getTestStr());
User test = (User) bf.getBean("testbean");
System.out.println(test.getUserName()+","+test.getEmail());
}
}
- 結果
二、自定義標籤的解析
1、整體過程
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
//獲取對應的名稱空間
String namespaceUri = getNamespaceURI(ele);
//根據名稱空間找到對應的NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//呼叫NamespaceHandler進行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
2、提取自定義標籤處理器
@Override
public NamespaceHandler resolve(String namespaceUri) {
//獲取所有已經配置的handler配置
Map<String, Object> handlerMappings = getHandlerMappings();
//根據名稱空間找到對應的資訊
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
//已經做過解析的,直接從快取中獲取
return (NamespaceHandler) handlerOrClassName;
}
else {
//沒有做過解析的,則返回的是類路徑
String className = (String) handlerOrClassName;
try {
//利用反射將類路徑轉化為類
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
//初始化類
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
//呼叫自定義的初始化方法
namespaceHandler.init();
//記錄在快取中
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}
3、標籤解析
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
parserContext.getReaderContext().error(ex.getMessage(), element);
return null;
}
}
return definition;
}