栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

dubbo源码系列3——dubbo自定义标签解析

dubbo源码系列3——dubbo自定义标签解析

        在梳理完dubbo spi 机制后【dubbo源码系列1——spi源码解读(上)dubbo源码系列2——spi源码解读(下)】
本节开始梳理dubbo provider的启动流程,因基于dubbo源码进行研究,因此直接采用dubbo源码中dubbo-demo模块中xml配置示例作为demo。
        本节将解析dubbo是如何利用spring进行自定义标签解析并注册到容器中,本节安排如下:

demo解析流程分析总结 一、demo

接口

public interface DemoService {

    String sayHello(String name);

    default CompletableFuture sayHelloAsync(String name) {
        return CompletableFuture.completedFuture(sayHello(name));
    }

}

接口实现

public class DemoServiceImpl implements DemoService {
    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);

    @Override
    public String sayHello(String name) {
        logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
    }

    @Override
    public CompletableFuture sayHelloAsync(String name) {
        CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
            return "async result";
        });
        return cf;
    }
}

启动

public class ApplicationP {
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-provider.xml");
        context.start();
    }
}

配置文件



    
        
    

    
    

    
    

    
    

    
    
    


二、解析流程分析 1、重要组件

dubbo.xsd
位于meta-INF下面,用于校验规范dubbo标签的编写;spring.schemas

http://dubbo.apache.org/schema/dubbo/dubbo.xsd=meta-INF/dubbo.xsd
http://code.alibabatech.com/schema/dubbo/dubbo.xsd=meta-INF/compat/dubbo.xsd

xsd规范链接与实际xsd文件存放位置映射关系

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

标签命名空间与实际解析handler映射关系

2、流程分析
->AbstractApplicationContext#refresh
 ->AbstractApplicationContext#obtainFreshBeanFactory
	->AbstractRefreshableApplicationContext#refreshBeanFactory
		->AbstractXmlApplicationContext#loadBeanDefinitions
			->AbstractXmlApplicationContext#loadBeanDefinitions
				->AbstractBeanDefinitionReader#loadBeanDefinitions
					->XmlBeanDefinitionReader#loadBeanDefinitions
						->XmlBeanDefinitionReader#doLoadBeanDefinitions
							->XmlBeanDefinitionReader#registerBeanDefinitions
								->DefaultBeanDefinitiondocumentReader#registerBeanDefinitions
									->DefaultBeanDefinitiondocumentReader#parseBeanDefinitions
								

spring加载xml并解析成beanDefinition流程比较长,本节重点关注spring如何解析自定义标签解生成beanDefintion并注册到容器。

DefaultBeanDefinitiondocumentReader#parseBeanDefinitions

	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;
					//判断节点的命名空间是否为默认的beans,如果不是则走自定义解析
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

比如dubbo:application节点如下:

BeanDefinitionParserDelegate#parseCustomElement

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        //获取节点的命名空间
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		  //this.readerContext.getNamespaceHandlerResolver()为DefaultNamespaceHandlerResolver
		NamespaceHandler 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));
	}

DefaultNamespaceHandlerResolver#resolve

	public NamespaceHandler resolve(String namespaceUri) {
	    //加载classpath下面所有的meta-INF/spring.handlers文件得到命名空间与handler的映射,如下截图所示
		Map handlerMappings = getHandlerMappings();
		//获取handler
		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");
				}
			    //实例化handler,dubbo对应为DubboNamespaceHandler
				NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
				//执行init方法
				namespaceHandler.init();
				handlerMappings.put(namespaceUri, namespaceHandler);
				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);
			}
		}
	}

DefaultNamespaceHandlerResolver#getHandlerMappings

private Map getHandlerMappings() {
		Map handlerMappings = this.handlerMappings;
		if (handlerMappings == null) {
			synchronized (this) {
				handlerMappings = this.handlerMappings;
				if (handlerMappings == null) {
					try {
				     	//加载meta-INF/spring.handlers文件
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);

						handlerMappings = new ConcurrentHashMap<>(mappings.size());
		
			                //复制properties到map中
							CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
						this.handlerMappings = handlerMappings;
					}
					catch (IOException ex) {
						throw new IllegalStateException(
								"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
					}
				}
			}
		}
		return handlerMappings;
	}


可以命名空间为http://dubbo.apache.org/schema/dubbo的标签应该用DubboNamespaceHandler解析;

DubboNamespaceHandler#init

    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("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());
    }

DubboNamespaceHandler#parse

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //获取注册接口
        BeanDefinitionRegistry registry = parserContext.getRegistry();
        
       
       registerAnnotationConfigProcessors(registry);
    
        //注册beanProcessor,比如ReferenceAnnotationBeanPostProcessor
        registerCommonBeans(registry);
        //调用DubboBeanDefinitionParser的parse方法进行解析
        BeanDefinition beanDefinition = super.parse(element, parserContext);
        setSource(beanDefinition);
        return beanDefinition;
    }

DubboBeanDefinitionParser#parse

private static RootBeanDefinition parse(Element element, ParserContext parserContext, Class beanClass, boolean required) {
         RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        //优先使用id,次优使用name,最后使用interface.如果包含相同的beanName,则通过增加后缀id来区分
        String id = resolveAttribute(element, "id", parserContext);
        if (StringUtils.isEmpty(id) && required) {
            String generatedBeanName = resolveAttribute(element, "name", parserContext);
            if (StringUtils.isEmpty(generatedBeanName)) {
                if (ProtocolConfig.class.equals(beanClass)) {
                    generatedBeanName = "dubbo";
                } else {
                    generatedBeanName = resolveAttribute(element, "interface", parserContext);
                }
            }
            if (StringUtils.isEmpty(generatedBeanName)) {
                generatedBeanName = beanClass.getName();
            }
            id = generatedBeanName;
            int counter = 2;
            while (parserContext.getRegistry().containsBeanDefinition(id)) {
                id = generatedBeanName + (counter++);
            }
        }
        if (StringUtils.isNotEmpty(id)) {
            if (parserContext.getRegistry().containsBeanDefinition(id)) {
                throw new IllegalStateException("Duplicate spring bean id " + id);
            }
            //手动注册
            parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
            beanDefinition.getPropertyValues().addPropertyValue("id", id);
        }
        //省略部分非关键代码
      }

可以看到通过parserContext.getRegistry().registerBeanDefinition(id, beanDefinition)将自定义schema标签解析成beanDefinition注册到beanDefinitionMap中,解析完如下所示:

三、 总结

        通过自定义命名空间找到自定义NamespaceHandler,通过自定义handler解析自定义标签生成beanDefinition注册到容器中。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/743310.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号