Spring自定义标签
一、标签解析原理:
1、Spring通过XML解析程序将其解析为DOM树,
2、通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition。
3、再通过Spring自身的功能对BeanDefinition实例化对象。
二、自定义标签步骤
1、定义三个文件
META-INF/soring.handlers 指定命名空间解析实现类
META-INF/spring.schemas 指定命名空间文件
META-INF/xxx.xsd 定义命名空间
2、实现NameSpace(命名空间)解析类(继承NamespaceHandlerSupport)
3、配置相应element元素的Parser(实现BeanDefinitionParser接口)和Bean(例如实现InitializingBean, DisposableBean,ApplicationContextAware, ApplicationListener,要看配置在element需要哪些属性)
三、应用案例
以dubbo框架为例,可以看到:
1、3个属性文件
META-INF/spring.handlers
http\://www.newlandframework.com/dubbo=com.newlandframework.rpc.spring.DubboNamespaceHandler
META-INF/spring.schemas
http\://www.newlandframework.com/dubbo/dubbo.xsd=META-INF/dubbo.xsd
dubbo.xsd
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.newlandframework.com/dubbo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.newlandframework.com/dubbo" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.springframework.org/schema/beans"/> <xsd:element name="service"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="interfaceName" type="xsd:string" use="required"/> <xsd:attribute name="ref" type="xsd:string" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> <xsd:element name="registry"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="ipAddr" type="xsd:string" use="required"/> <xsd:attribute name="protocol" type="xsd:string" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> <xsd:element name="reference"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="interfaceName" type="xsd:string" use="required"/> <xsd:attribute name="ipAddr" type="xsd:string" use="required"/> <xsd:attribute name="protocol" type="xsd:string" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> </xsd:schema>
2、Handler解析类
DubboNamespaceHandler
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.config.spring.schema; import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.config.*; import com.alibaba.dubbo.config.spring.AnnotationBean; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.ServiceBean; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * DubboNamespaceHandler * * @export */ public class DubboNamespaceHandler extends NamespaceHandlerSupport { static { Version.checkDuplicate(DubboNamespaceHandler.class); } public void init() { registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true)); registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true)); registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true)); registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true)); registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true)); registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true)); registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true)); registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true)); registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false)); registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true)); } }
3、定义parser解析bean文件
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.config.spring.schema; import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.config.*; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.rpc.Protocol; import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Date; import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; /** * AbstractBeanDefinitionParser * * @export */ public class DubboBeanDefinitionParser implements BeanDefinitionParser { private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class); private static final Pattern GROUP_AND_VERION = Pattern.compile("^[\\-.0-9_a-zA-Z]+(\\:[\\-.0-9_a-zA-Z]+)?$"); private final Class<?> beanClass; private final boolean required; public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) { this.beanClass = beanClass; this.required = required; } ...... }