Dubbo服务导出方式

Dubbo导出服务方式主要

  1. xml方式
  2. 注解方式

xml配置方式

dubbo服务xml导出方式示例:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
	<bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>

    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService" version="1"/>
</beans>

对于dubbo来说,通过spring提供的xml扩展来解析dubbo自定义的标签,如果要自定义标签通过spring解析,主要步骤有以下几步:

  1. schema文件用来定义xml文件编写规范,定义有哪些标签,有什么属性
  2. NameSpaceHandler(命名空间处理器)—向spring中添加标签处理器
  3. 服务重启时dubbo注册节点什么时候下掉 dubbo服务注解_spring

  4. 编写spring.handlers文件,用来绑定命名空间解析类(NamespaceHandlerSupport)
  5. 服务重启时dubbo注册节点什么时候下掉 dubbo服务注解_xml_02

  6. 编写spring.schemas文件,指定xsd文件位置
  7. 服务重启时dubbo注册节点什么时候下掉 dubbo服务注解_spring_03

  8. 编写标签处理器类,继承BeanDefinitionParser,重写它点parse方法
  9. 服务重启时dubbo注册节点什么时候下掉 dubbo服务注解_spring_04

下面我们主要来分析BeanDefinitionParser标签处理器怎么来处理的?

  1. dubbo的标签解析代码很长,主要的功能就是把dubbo服务的标签解析成ServiceBeanBeanDefinition并且给他赋予各个属性的值.
  2. 在解析dubbo服务xml的时候,spring中的bean对象还没有创建好,这个时候需要dubbo服务实现类的bean对象,是获取不到的,只能使用它的bean名称,使用bean名称的占位符对象RuntimeBeanReference完成属性填充,对应配置文件内容如下:
<bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>

    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService" version="1"/>

如果导出时的Dubbo接口实现类是使用class属性填写的全路径类名称,那么在设置ServiceBeanBeanDefinition使用的属性就是使用BeanDefinitionHolder

<dubbo:service interface="org.apache.dubbo.demo.DemoService" 
    class="org.apache.dubbo.demo.provider.DemoServiceImpl" 
    version="1"/>

BeanDefinitionHolderRuntimeBeanReference 都是在属性填充的时候会解析出他们对应的真正的bean对象

注解方式

使用@EnableDubbo注解开始 查看@DubboService @DubboRefence解析过程

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {}

@EnableDubbo注解代码中可以看出来,使用了@Import注解导入了DubboComponentScanRegistrar类进行服务导出解析

@DubboService注解通过DubboComponentScanRegistrar添加了服务导出的解析类

public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
    	//解析@service
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);

        // @since 2.7.6 Register the common beans
        registerCommonBeans(registry);
    }
    
    private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        builder.addConstructorArgValue(packagesToScan);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);

    }
}

ServiceClassPostProcessorServiceAnnotationBeanPostProcessor的父类,它实现了BeanDefinitionRegistryPostProcessor接口,可以往BeanFactory中添加BeanDefinition

public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
        ResourceLoaderAware, BeanClassLoaderAware {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        // @since 2.7.5
        registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);

        Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

        if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
            //注册@DubboService
            registerServiceBeans(resolvedPackagesToScan, registry);
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
            }
        }

    }
}

总结

  • 通过注解或者 xml导出的每个dubbo服务 最后都会变成变成一个ServiceBean extend ServiceConfig
  • 服务导出都是借助spring中的扩展完成的BeanDefinition以及bean对象生成