dubbo源码解析之dubbo配置解析

文章系列

一、dubbo源码解析之框架粗谈
二、dubbo源码解析之dubbo配置解析
三、dubbo源码解析之服务发布与注册
四、dubbo源码解析之服务发现
五、dubbo源码解析之服务调用(通信)流程
六、dubbo获取服务提供者IP列表

一、Spring 解析自定义配置

我们在 Spring 的 xml 配置文件里经常定义各种各样的配置(tx、bean、mvc、bean等等),以及集成第三方框架时,也会看到一些 Spring 之外的配置,例如 mybatis 的配置、dubbo 的配置、redis 的配置等等。
看到这里,是否会引发我们思考,Spring 是如何解析这些 xml 配置文件呢???

在 Spring 我们通过创建一个 ClassPathXmlApplicationContext 来解析、加载以及初始化 Spring 上下文,其构造方法代码如下:

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			// 重启、刷新、重置
			refresh();
		}
	}
}

在其构造方法中,会调用一个 refresh() 方法,进行 Spring 重启、刷新、重置动作,这也是 Spring 的入口方法。

refresh() 方法中,会加载扫描所有 META-INF/spring.handlers 文件,调用链路如下:

ClassPathXmlApplicationContextAbstractApplicationContext#refresh()    // 刷新AbstractApplicationContext#obtainFreshBeanFactory()AbstractRefreshableApplicationContext#refreshBeanFactory()		// 刷新AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory beanFactory)	// 加载 BeanDefinitionAbstractXmlApplicationContext#loadBeanDefinitions(XmlBeanDefinitionReader reader)		// 加载xml 中的 BeanDefinitionAbstractBeanDefinitionReader#loadBeanDefinitions(Resource... resources)XmlBeanDefinitionReader#loadBeanDefinitions(Resource resource)XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource encodedResource)XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource)		// 加载xml 中的 BeanDefinitionXmlBeanDefinitionReader#registerBeanDefinitions(Document doc, Resource resource)		// 解析doc,注册对应的 BeanDefinitionDefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element root)	// 解析doc,注册对应的 BeanDefinition

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)	// 解析BeanDefinitionParserDelegate#parseCustomElement(Element ele)	// 没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点
																// 如果使用Spring的Bean规则解析元素节点,则调用DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法BeanDefinitionParserDelegate#parseCustomElement(Element ele, @Nullable BeanDefinition containingBd)DefaultNamespaceHandlerResolver#resolve(String namespaceUri)	// 根据namespaceUri 获取对应的NamespaceHandlerDefaultNamespaceHandlerResolver#getHandlerMappings()	// 获取所有 handlerMappings 映射

DefaultNamespaceHandlerResolver#getHandlerMappings() 方法,获取所有 handlerMappings 映射。

public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
	// 默认Handler映射文件
	public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
	
	public DefaultNamespaceHandlerResolver() {
		this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
	}
	
	private Map<String, Object> getHandlerMappings() {
		Map<String, Object> handlerMappings = this.handlerMappings;
		if (handlerMappings == null) {
			synchronized (this) {
				handlerMappings = this.handlerMappings;
				if (handlerMappings == null) {
					try {
						// 将classpath下的 META-INF/spring.handlers 中的配置加载到Map中
						// this.handlerMappingsLocation = META-INF/spring.handlers
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						if (logger.isDebugEnabled()) {
							logger.debug("Loaded NamespaceHandler mappings: " + mappings);
						}
						Map<String, Object> mappingsToUse = new ConcurrentHashMap<>(mappings.size());
						CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse);
						
						// key   -> NamespaceUrl
						// value -> NamespaceHandler
						handlerMappings = mappingsToUse;
						this.handlerMappings = handlerMappings;
					}
					catch (IOException ex) {
						throw new IllegalStateException(
								"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
					}
				}
			}
		}
		return handlerMappings;
	}

Spring 在启动过程中,将所有 classpath 下的 META-INF/spring.handlers 文件中的配置加载到一个 Map<String, Object> handlerMappings 中,该 Map 存储了从命名空间 URI 到 NamespaceHandler 类名实例的映射,其中 NamespaceUrl 为key,对应的 NamespaceHandler 为value,例如 dubbo 中的 META-INF/spring.handlers 内容如下:

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

最后,会在 DefaultNamespaceHandlerResolver#resolve(String namespaceUri) 方法中,调用 handlerMappings 中的 NamespaceHandlerinit() 方法,逻辑如下:

public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
	public NamespaceHandler resolve(String namespaceUri) {
		// 获取handlerMappings
		Map<String, Object> handlerMappings = getHandlerMappings();
	
		// 通过 namespaceUri,获取对应的 NamespaceHandler
		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 = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
				// 调用其 init() 方法,完成初始化
				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);
			}
		}
	}
}

二、编写一个 Spring 自定义配置

完成一个Spring的自定义配置一般需要下面几步:

  1. 定义Java Bean
  2. 编写XSD(XML Schema)文件,用于校验XML
  3. 编写 NameSpaceHandler 和 BeanDefinitionParser 完成解析工作
  4. 编写 spring.handlersspring.schemas 串联起所有部件
  5. 编写自定义配置文件xml
  6. 应用

2.1 定义Java Bean

@Data
public class People {
    private String id;
    private String name;
    private Integer age;
}

2.2 编写XSD(XML Schema)文件

用于校验XML,定义了一些列的语法来规范XML,存放在 resources/META-INF/ 目录下,如:
在这里插入图片描述
people.xsd 内容如下:

<xsd:schema xmlns="http://code.test.com/schema/people"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        targetNamespace="http://code.test.com/schema/people"
        elementFormDefault="qualified">
 
        <xsd:import namespace="http://www.springframework.org/schema/beans"/>
        
        <xsd:element name="people">
            <xsd:complexType>
                <xsd:complexContent>
                    <xsd:extension base="beans:identifiedType">
                        <xsd:attribute name="name" type="xsd:string"/>
                        <xsd:attribute name="age" type="xsd:int"/>
                    </xsd:extension>
                </xsd:complexContent>
            </xsd:complexType>
        </xsd:element>
</xsd:schema>

2.3 编写 NameSpaceHandler 和 BeanDefinitionParser 完成解析工作

NameSpaceHandler

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
 
public class MyNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("people", new PeopleBeanDefinitionParser());
    }
}

PeopleBeanDefinitionParser

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
 
public class PeopleBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected Class getBeanClass(Element element){
        return People.class;
    }
    @Override
    protected void doParse(Element element, BeanDefinitionBuilder bean){
        String name = element.getAttribute("name");
        String age = element.getAttribute("age");
        String id = element.getAttribute("id");
        if (StringUtils.hasText(name)) {
            bean.addPropertyValue("name",name);
        } if (StringUtils.hasText(age)) {
            bean.addPropertyValue("age",Integer.valueOf(age));
        } if (StringUtils.hasText(id)) {
            bean.addPropertyValue("id",id);
        }
    }
}

2.4 编写 spring.handlersspring.schemas

编写 spring.handlersspring.schemas ,用于串联所有部件,存放在 resources/META-INF/ 目录下,如:
在这里插入图片描述

spring.handlers 内容如下:

http\://code.test.com/schema/people=com.example.schema.MyNamespaceHandler

spring.schemas 内容如下:

http\://code.test.com/schema/people.xsd=META-INF/people.xsd

2.5 编写自定义配置文件xml

<?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:test="http://code.test.com/schema/people"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://code.test.com/schema/people http://code.test.com/schema/people.xsd
 
">
    <test:people id="people" name="testName" age="100"/>
</beans>

2.6 应用

import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class SchemaMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/MyName.xml");
        People people =(People) context.getBean("people");
        System.out.println(people.getName());
    }
}

三、dubbo 中的 Spring 配置

dubbo 通过 Spring 提供的自定义配置解析,完成了与 Spring 的整合,内容如下:
在这里插入图片描述
其中 spring.handlers 内容如下:

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

3.1 DubboNamespaceHandler

Spring 在装载 DubboNamespaceHandler 时,会自动调用其 init() 方法,通过注册一个BeanDefinitionParser 解析器,完成Bean对象的注册,如下:。

public class DubboNamespaceHandler extends NamespaceHandlerSupport implements ConfigurableSourceBeanMetadataElement {
	@Override
    public void init() {
    	// 注册 Bean 定义解析器
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
        registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
        registerBeanDefinitionParser("ssl", new DubboBeanDefinitionParser(SslConfig.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, true));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
}

3.2 DubboBeanDefinitionParser

Spring 会自动调用 BeanDefinitionParser 中的 BeanDefinition parse(Element element, ParserContext parserContext) 方法,解析指定的 Element ,并注册到其 IOC 容器中。

public class DubboBeanDefinitionParser implements BeanDefinitionParser {
	@Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
    	// 解析
        return parse(element, parserContext, beanClass, required);
    }
}

参考文档https://www.cnblogs.com/huan30/p/12790406.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值