dubbo 配置管理机制以及源代码分析

dubbo 框架强大在于完美的和Spring进行了整合,由于现在大部分的java程序都建立在Spring框架上,所以一种java rpc框架能否方便java coder去开发和使用,关键点在于该rpc框架能否提供类似于Spring的配置管理。dubbo 无疑在配置项管理上无疑是十分强大的。下面来详细讲解一下dubbo的配置。

1.dubbo配置的启动时机

   dubbo的配置启动 是随着Spring的配置文件的拉起而开始运转。dubbo源代码 中的 dubbo-config 下面的dubbo-config-api和dubbo-config-spring是负责整个dubbo的Spring配置管理。 在整个外部程序Spring配置文件拉起时,Spring将会读取到dubbo-config-spring工程下的spring.handlers和spring.schemas,从而感知道了dubbo Spring配置文件的schema的存在。spring.schemas文件中配置这dubbo 的xml schema 和对应的schema 文件,内容如下:http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd。 在dubbo.xsd文件中,定义了dubbo 支持的xml标签和相应的xml validation。如下大致如下:


在加载完了dubbo spring schema,Spring将会解析spring.handlers文件中http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler。 dubbo 通过DubboNameSpaceHandler来进行dubbo Spring配置的相应解析。


2.dubbo Spring 配置的解析流程

在Spring加载进spring.handlers后,会执行com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler。DubboNamespaceHandler的源代码如下:

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

}

通过源码我们知道,DubboNamespaceHandler继成自Spring的 NamespaceHandlerSupport。因此不需要实现所有的解析工作,只要将自定义schema中的元素解析器注册进来就可以。在DubboBeanDefinitionParser中完成我们熟悉的<dubbo:application /> <dubbo:provider /> <dubbo:consumer />中dubbo 标签的解析工作。DubboBeanDefinitionParser的核心代码如下如下:
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
    
    private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);
	
    private final Class<?> beanClass;
    
    private final boolean required;

    public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
        this.beanClass = beanClass;
        this.required = required;
    }

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return parse(element, parserContext, beanClass, required);
    }
    
    @SuppressWarnings("unchecked")
    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        String id = element.getAttribute("id");
        if ((id == null || id.length() == 0) && required) {
        	String generatedBeanName = element.getAttribute("name");
        	if (generatedBeanName == null || generatedBeanName.length() == 0) {
        	    if (ProtocolConfig.class.equals(beanClass)) {
        	        generatedBeanName = "dubbo";
        	    } else {
        	        generatedBeanName = element.getAttribute("interface");
        	    }
        	}
        	if (generatedBeanName == null || generatedBeanName.length() == 0) {
        		generatedBeanName = beanClass.getName();
        	}
            id = generatedBeanName; 
            int counter = 2;
            while(parserContext.getRegistry().containsBeanDefinition(id)) {
                id = generatedBeanName + (counter ++);
            }
        }
        if (id != null && id.length() > 0) {
            if (parserContext.getRegistry().containsBeanDefinition(id))  {
        		throw new IllegalStateException("Duplicate spring bean id " + id);
        	}
            parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
            beanDefinition.getPropertyValues().addPropertyValue("id", id);
        }
        if (ProtocolConfig.class.equals(beanClass)) {
            for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
                BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
                PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
                if (property != null) {
                    Object value = property.getValue();
                    if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                        definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                    }
                }
            }
        } else if (ServiceBean.class.equals(beanClass)) {
            String className = element.getAttribute("class");
            if(className != null && className.length() > 0) {
                RootBeanDefinition classDefinition = new RootBeanDefinition();
                classDefinition.setBeanClass(ReflectUtils.forName(className));
                classDefinition.setLazyInit(false);
                parseProperties(element.getChildNodes(), classDefinition);
                beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
            }
        } else if (ProviderConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
        } else if (ConsumerConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
        }


通过源码,我们可以看到DubboBeanDefinitionParser继成Spring的BeanDefinitionParser,通过执行parse方法,从而实现把每个dubbo自定义的spring 标签实例化成我们熟悉的spring BeanDefinition。至此,就完成了dubbo 自定义的spring 标签转化成普通的Spring bean,从而可以在工程中作为Spring bean灵活的使用和@Autowired. 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值