从源码角度一步步窥探Dubbo服务发布原理

@DubboComponentScan注解

我们在使用Dubbo时,在没有使用阿里的starter时,都会在启动类打上@DubboComponentScan这个注解来将我们被Dubbo的@service注解标注的类,注册到Spring IOC容器中。这个注解很关键,Dubbo服务的发布,以及引用都从此注解开始。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
   
   
// 省略注解属性
}

注解里Import了DubboComponentScanRegistrar这个类,从字面上就能大致理解是做什么用的了–扫描Dubbo的组件并将其注册。我们看看这个类具体长什么样并干些什么。

public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
   
   
}

DubboComponentScanRegistrar 实现了spring 提供的ImportBeanDefinitionRegistrar接口。这个接口对于扩展spring非常重要,其作用是注册BeanDefinition。熟悉spring的应该会知道,spring在注册bean前,会将扫描的bean组装成BeanDefinition。由于这里不是讲解spring IOC原理,就不过多赘述,后续再另开篇幅写IOC原理。ImportBeanDefinitionRegistrar接口定义如下:

public interface ImportBeanDefinitionRegistrar {
   
   

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {
   
   
			
		// 忽略BeanNameGenerator 转发调用其重载的另一个registerBeanDefinitions方法
		registerBeanDefinitions(importingClassMetadata, registry);
	}

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
   
	}

我们再看看DubboComponentScanRegistrar 是如何实现重写ImportBeanDefinitionRegistrar的接口:

public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
   
   

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

		// 解析@service注解,获取将要扫描的包路径集合
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
		// 后置处理器--将带有@service注解的类解析并注册到Ioc容器中,并export进行服务暴露
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
		// 后置处理器--将带有@Reference注解的类解析并注册到IOC容器中,并初始化ReferenceBeanInvocationHandler,代理执行invoke进行服务调用
        registerReferenceAnnotationBeanPostProcessor(registry);

    }
    // 省略其他代码....
  }

由于篇幅限制,本文着重分析Dubbo的发布原理,调用原理将另起篇幅分析。

我们先分析getPackagesToScan方法,看看Dubbo是如何处理获取包路径的。在分析之前,我们先看看这个DubboComponentScan注解有哪些属性

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

    String[] value() default {
   
   };

    String[] basePackages() default {
   
   };

    Class<?>[] basePackageClasses() default {
   
   };
}

接着具体看看getPackagesToScan的操作

private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
   
   
		// 获取DubboComponentScan注解的注解属性,这里的AnnotationAttributes类在spring源码中也是能寻觅到其踪迹的。
		// AnnotationAttributes是spring抽出来的注解属性对象,与其经常配对出现的就是spring封装的工具类AnnotationUtils和AnnotatedElementUtils
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
        // 获取注解的basePackages属性值
        String[] basePackages = attributes.getStringArray("basePackages");
        // 获取注解的basePackageClasses属性值
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
        // 获取注解的value属性值
        String[] value = attributes.getStringArray("value");
        // 用value 初始化一个packagesToScan 集合
        Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
        // 添加basePackages的值
        packagesToScan.addAll(Arrays.asList(basePackages));
        // 遍历basePackageClasses,将制定的类所处的包路径也添加到packagesToScan集合中
        for (Class<?> basePackageClass : basePackageClasses) {
   
   
            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        // 如果从三处basePackages、basePackageClasses、value获取的包路径都为空
        // 返回该注解所标注的当前类所处的包路径作为packagesToScan
        // 从此处我们就可以知道为什么@DubboComponentScan为何通常标注在启动类上的原因了
        if (packagesToScan.isEmpty()) {
   
   
            return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啊杰eboy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值