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); // 解析默认标签
} else {
delegate.parseCustomElement(ele); // 解析自定义标签
}
}
}
} else {
delegate.parseCustomElement(root); // 解析自定义标签
}
}
delegate.parseCustomElement(root); // 解析自定义标签
举例:
Step1:创建user实体:
@Data
public class User {
private String id;
private String name;
private String email;
}
Step2:定义一个XSD文件描述组件内容:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://www.muse.com/schema/user"
elementFormDefault="qualified">
<element name="user">
<complexType>
<attribute name="id" type="string"/>
<attribute name="name" type="string"/>
<attribute name="email" type="string"/>
</complexType>
</element>
</schema>
Step3:创建BeanDefinitionParser接口的实现类,用来解析XSD文件中的定义和组件定义。
/**
* 自定义标签解析器
*/
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
return User.class;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String id = element.getAttribute("id");
String name = element.getAttribute("name");
String email = element.getAttribute("email");
if (StringUtils.hasText(id)) builder.addPropertyValue("id", id);
if (StringUtils.hasText(name)) builder.addPropertyValue("name", name);
if (StringUtils.hasText(email)) builder.addPropertyValue("email", email);
}
}
以上代码的意思:从element里面读数据,读出来之后写到builder里面。
Step4:创建NamespaceHandlerSupport实现类,目的是将组件注册到Spring容器中,用来维护注册关系
/**
* 自定义标签注册器
*/
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}
Step5:编写spring.handlers和spring.schemas文件,默认位置是/META-INF目录下
spring.handlers文件内容:
https\://www.muse.com/schema/user=com.muse.springdemo.custom.UserNamespaceHandler
spring.schemas内容:
https\://www.muse.com/schema/user.xsd=META-INF/user.xsd
Step6:在配置文件bean.xml中引入对应的命名空间以及XSD之后,就可以配置<myname:user …/>了
<?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:muse="https://www.muse.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
https://www.muse.com/schema/user
https://www.muse.com/schema/user.xsd" default-autowire="no">
使用自定义 标签:
<!-- 自定义标签演示 -->
<muse:user id="customUser" name="muse" email="muse@163.com" />
代码解析:
Step3的创建BeanDefinitionParser接口的实现类:UserBeanDefinitionParser
父类:AbstractSingleBeanDefinitionParser --> 父类:AbstractBeanDefinitionParser --> 实现接口:BeanDefinitionParser --> 方法:BeanDefinition parse(Element var1, ParserContext var2);
Step4的创建NamespaceHandlerSupport实现类:UserNamespaceHandler
父类:NamespaceHandlerSupport --> --> 实现接口:NamespaceHandler --> 方法:void init()
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
private final Map<String, BeanDefinitionParser> parsers = new HashMap();
测试运行:
@Test
void testCustom() {
User customUser = beanFactory.getBean("customUser", User.class);
log.info("customUser={}", customUser);
}
运行结果:
源码解析:
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
return this.parseCustomElement(ele, (BeanDefinition)null);
}
对于自定义标签的解析操作,是在parseCustomElement方法中完成的,具体来说有如下3 个步骤:
① 获得namespaceUri,此处是通过org.w3c.dom.Node中的getNamespaceURI()方法进 行获取的;
② 获得解析该自定义标签的NamespaceHandler实现类。
③ 调用该实现类的parse(...)方法进行解析操作。
/**
* 解析自定义元素(在默认命名空间之外)
*/
// eg1:containingBd=null
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
/** 1:获得命名空间 */
String namespaceUri = getNamespaceURI(ele); // eg1:namespaceUri="https://www.muse.com/schema/user"
if (namespaceUri == null) return null;
/** 2:获得解析该自定义标签的NamespaceHandler实现类handler */
// this.readerContext.getNamespaceHandlerResolver() 为:DefaultNamespaceHandlerResolver
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) { // eg1:handler=UserNamespaceHandler@2641
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
/** 3:通过handler进行解析操作 */
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); // eg1:NamespaceHandlerSupport#parse(...)
}
/** 获取入参节点的命名空间URI(namespace URI)*/
@Nullable
public String getNamespaceURI(Node node) {
return node.getNamespaceURI(); // eg1:return "http://www.springframework.org/schema/beans"
}
node是w3c的。
/**
* 从配置的映射中找到提供的命名空间URI的NamespaceHandler
*/
// eg1:namespaceUri="https://www.muse.com/schema/user"
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
/** 1:延迟加载指定的NamespaceHandler映射,默认加载路径:"META-INF/spring.handlers" */
Map<String, Object> handlerMappings = getHandlerMappings();
/** 2:通过namespaceUri,获取对应的NamespaceHandler实现类 */
Object handlerOrClassName = handlerMappings.get(namespaceUri); // eg1: handlerOrClassName="com.muse.springdemo.custom.UserNamespaceHandler"
/** 3-1:如果没找到,则返回null */
if (handlerOrClassName == null) // eg1: false
return null;
/** 3-2:如果找到了,并且是NamespaceHandler类型,则返回 */
else if (handlerOrClassName instanceof NamespaceHandler) // eg1: false
return (NamespaceHandler) handlerOrClassName;
/** 3-3:如果是字符串类型的,则转换为NamespaceHandler类型 */
else {
String className = (String) handlerOrClassName; // eg1:className="com.muse.springdemo.custom.UserNamespaceHandler"
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);
/** 3-3-1:调用init()方法执行初始化操作 */
namespaceHandler.init(); // eg1:UserNamespaceHandler#init()
/** 3-3-2:将namespaceHandler实例对象,维护到映射中 */
handlerMappings.put(namespaceUri, namespaceHandler); // eg1:namespaceUri="https://www.muse.com/schema/user",namespaceHandler=UserNamespaceHandler@2641
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
1:延迟加载指定的NamespaceHandler映射,默认加载路径
resolve获得解析该自定义标签的NamespaceHandler实现类:
首先,通过调用getHandlerMappings()方法,延迟加载指定的NamespaceHandler映射, 默认加载路径:"META-INF/spring.handlers"。
其次,通过namespaceUri,获取对应的NamespaceHandler实现类:
① 如果没找到,则返回null;如果找到了NamespaceHandler,则返回
② 如果是字符串类型的,则转换为NamespaceHandler类型,并且调用init()方法进行 初始化操作,然后将namespaceUri和namespaceHandler维护到handlerMappings映 射中,最后将namespaceHandler进行返
/**
* 延迟加载指定的NamespaceHandler映射,默认加载路径:"META-INF/spring.handlers"
*/
private Map<String, Object> getHandlerMappings() {
// eg1: handlerMappings=[
// "http://www.springframework.org/schema/aop" -> "org.springframework.aop.config.AopNamespaceHandler",
// "http://www.springframework.org/schema/task" -> "org.springframework.scheduling.config.TaskNamespaceHandler",
// "http://www.springframework.org/schema/lang" -> "org.springframework.scripting.config.LangNamespaceHandler",
// "http://www.springframework.org/schema/c" -> "org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler",
// "https://www.muse.com/schema/user" -> "com.muse.springdemo.custom.UserNamespaceHandler",
// "http://www.springframework.org/schema/jee" -> "org.springframework.ejb.config.JeeNamespaceHandler",
// "http://www.springframework.org/schema/cache" -> "org.springframework.cache.config.CacheNamespaceHandler",
// "http://www.springframework.org/schema/p" -> "org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler",
// "http://www.springframework.org/schema/util" -> "org.springframework.beans.factory.xml.UtilNamespaceHandler",
// "http://www.springframework.org/schema/context" -> "org.springframework.context.config.ContextNamespaceHandler",
// "http://www.springframework.org/schema/mvc" -> "org.springframework.web.servlet.config.MvcNamespaceHandler"]
Map<String, Object> handlerMappings = this.handlerMappings;
/** 1:如果handlerMappings为空,则通过加载"META-INF/spring.handlers"文件来获得handlerMappings列表 */
if (handlerMappings == null) { // eg1: false
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) { // double check
try {
// handlerMappingsLocation="META-INF/spring.handlers"
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
handlerMappings = new ConcurrentHashMap<>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
/** 2:如果handlerMappings不为空,则直接返回即可 */
return handlerMappings;
}
/** 3-3-1:调用init()方法执行初始化操作 */
/**
* 自定义标签注册器
*/
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
parsers是一个hashmap。
/** 3:通过handler进行解析操作 */
handler=UserNamespaceHandler@2641
/** 3:通过handler进行解析操作 */
return handler.parse(ele,
new ParserContext(this.readerContext, this, containingBd));
// eg1:NamespaceHandlerSupport#parse(...)
NamespaceHandlerSupport#parse(...):
在parse(...)方法中我们可以看到,首先是通过findParserForElement方法来找到 localName对应的解析器。以上面的示例为例,在bean.xml中配置的是<muse:user id="customUser" name="muse" email="muse@163.com" />
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = this.findParserForElement(element, parserContext);
return parser != null ? parser.parse(element, parserContext) : null;
}
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element); // user
BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
此时的parser是UserBeanDefinitionParser对象, 不为空,于是走parser.parse(element, parserContext)。
针对:
<!-- 自定义标签演示 -->
<muse:user id="customUser" name="muse" email="muse@163.com" />
先解析出一个definition,然后再注册进去。
@Nullable
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = this.parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = this.resolveId(element, definition, parserContext); // id为customUser
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; // muse
if (this.shouldParseNameAsAliases()) {
String name = element.getAttribute("name"); // muse
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
this.registerBeanDefinition(holder, parserContext.getRegistry());
if (this.shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
this.postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
} catch (BeanDefinitionStoreException var8) {
BeanDefinitionStoreException ex = var8;
String msg = ex.getMessage();
parserContext.getReaderContext().error(msg != null ? msg : ex.toString(), element);
return null;
}
}
return definition;
}
protected void registerBeanDefinition(BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definition, registry);
}
beanName的注册和alias的注册:
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
解析definition的过程:
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = this.getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
Class<?> beanClass = this.getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
} else {
String beanClassName = this.getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
builder.setLazyInit(true);
}
this.doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
this.doParse(element, builder);
}
至此通过代码的方式将customUser这个bean注册进去了。
1h42min: 总结。