本次的文章的版本都是基于 2.7.7 版本的。 2.7.7提供了@EnableDubbo注解来用于和spring整合。

对于Import注解的源码的讲解,推荐看下这篇博客, 讲的十分清楚明白: https://blog.csdn.net/boling_cavalry/article/details/82530167

从Spring中 Dubbo的使用上面来看,有两个重要的注解,即@DubboService 和 @DubboReference。
对两个注解的解析分别在 ServiceAnnotationBeanPostProcessor和ReferenceAnnotationBeanPostProcessor。 本文章会从Dubbo的注解启动开始追溯,最后到ServiceAnnotationBeanPostProcessor的作用原理解析, 关于ReferenceAnnotationBeanPostProcessor的作用原理在下篇文章中说明

@EnableDubbo注解


这个注解上面也有@EnableDubboConfig和@DubboComponentScan两个注解。

Spring已经提供了注解的注解功能, 可以实现类似的注解的继承的功能。 比如springboot的著名的@SpringBootApplication注解。 所以实际是EnableDubboConfig和DubboComponentScan两个注解真正起作用。

@EnableDubboConfig注解

可以看到@Import 注解,@Import又是一个spring很重要的注解,并且必须和Configuration注解配置和使用,才会生效 ,所以可以推导知道EnableDubbo注解也必须要和Configuration注解一起配合使用。

此处勘误, 经过我自己测试发现, 配合@Component注解一起使用也可以。

@Import注解可以实现导入第三方的包的bean到容器的功能,配合注解Configuration一起使用, 可以实现一个注解就可以注入第三方bean的能力,也就是EnableDubbo这一个注解可以标识dubbo启动与否的原理。

可以看到图中的@Import注解的参数DubboConfigConfigurationRegistrar类。

DubboConfigConfigurationRegistrar 类


图中方法名可以看到有三个方法都注入bean到容器中了

registerBeans(registry, DubboConfigConfiguration.Single.class);

 /*** Register Beans if not present in {@link BeanDefinitionRegistry registry}** @param registry         {@link BeanDefinitionRegistry}* @param annotatedClasses {@link Annotation annotation} class*/public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {if (ObjectUtils.isEmpty(annotatedClasses)) {return;}Set<Class<?>> classesToRegister = new LinkedHashSet<Class<?>>(asList(annotatedClasses));// Remove all annotated-classes that have been registeredIterator<Class<?>> iterator = classesToRegister.iterator();while (iterator.hasNext()) {Class<?> annotatedClass = iterator.next();if (isPresentBean(registry, annotatedClass)) {iterator.remove();}}AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);if (logger.isDebugEnabled()) {logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + asList(annotatedClasses) + " .");}//这里就会包传入的Class参数d对应的类加入到容器中reader.register(classesToRegister.toArray(EMPTY_CLASS_ARRAY));}

源码中会使用AnnotatedBeanDefinitionReader 将传入的DubboConfigConfiguration.Single类放入容器中。

DubboConfigConfiguration.Single类


可以看到最后使用的还是使用了EnableConfigurationBeanBinding注解,这个注解是Spring 自带的

再往深层追溯, ConfigurationBeanBindingRegistrar类,代码太多了,只截图重点方法。

从源码中可以看到,会把EnableConfigurationBeanBinding注解中传入的type参数作为BeanDefinition放入容器, 同时还会把配置中以prefix参数值作为配置的key的前缀的value注入到这个Bean中。 这个至于怎么把配置注入bean中, 我还没有明白, 需要后面查找。

到这一步就把dubbo相关的config对象全部注入到容器中了。 同时也把一些配置信息注入到正确的config了

@DubboComponentScan

上面只是弄明白了dubbo的一些配置对象如何注入容器中, 但是关于Dubbo的一些Service是如何注入到容器的。 我们看下DubboComponentScan注解的源码。

看下DubboComponentScanRegistrar类

/*** Dubbo {@link DubboComponentScan} Bean Registrar** @see Service* @see DubboComponentScan* @see ImportBeanDefinitionRegistrar* @see ServiceAnnotationBeanPostProcessor* @see ReferenceAnnotationBeanPostProcessor* @since 2.5.7*/
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//看方法名猜到是获取包路径 , 进入下面的源码中看下Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);// @since 2.7.6 Register the common beansregisterCommonBeans(registry);}/*** Registers {@link ServiceAnnotationBeanPostProcessor}** @param packagesToScan packages to scan without resolving placeholders* @param registry       {@link BeanDefinitionRegistry}* @since 2.5.8*/private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {//先放入ServiceAnnotationBeanPostProcessor类的bean到容器中。 并且把路径作为参数传入这个类BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);builder.addConstructorArgValue(packagesToScan);builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);}/***  获取注解中配置的需要扫描的包的路径信息*/private Set<String> getPackagesToScan(AnnotationMetadata metadata) {//获取注解中的所有属性AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));//获取配置的路径信息String[] basePackages = attributes.getStringArray("basePackages");Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");String[] value = attributes.getStringArray("value");// Appends value array attributesSet<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));packagesToScan.addAll(Arrays.asList(basePackages));for (Class<?> basePackageClass : basePackageClasses) {packagesToScan.add(ClassUtils.getPackageName(basePackageClass));}if (packagesToScan.isEmpty()) {return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));}return packagesToScan;}}

ServiceAnnotationBeanPostProcessor类

ServiceAnnotationBeanPostProcessor类在我的上一篇文章中有讲解
https://blog.csdn.net/leisurelen/article/details/106993692

这个类的作用就是扫描传入的路径, 并且扫描路径中所有类的注解, 如果有DubboService 和Service 注解就会生成对应的Beandefinition放入容器中。

理解这个类有一个前置知识必须了解, 就是ClassPathBeanDefinitionScanner类, 这个是Spring的类,用来扫描项目中特定的注解的类,并把这个类放入容器中, Dubbo就是使用这个类的功能来扫描项目中的DubboService注解并生成BeanDefinition放入容器中的。

具体流程:

  1. 生成事件监听器类DubboBootstrapApplicationListener 的BeanDefinition放入容器中,这个是 @since 2.7.5版本新增的
  2. 解析处理下传入的路径
  3. 生成DubboClassPathBeanDefinitionScanner类来扫描路径下的类。这个类继承自ClassPathBeanDefinitionScanner类,dubbo没做很大修改,只是传入environment 和resourceLoader 两个对象, 同时在scanner中 增加了两个注解过滤器DubboService和Service, 并且禁用了spring的默认过滤器,也就是Spring的bean不会被扫描到。下图就是传入参数禁用useDefaultFilters。
    org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner
  4. 扫描路径下的类,这时候scanner就会把DubboService和Service注解的类扫描到容器中了, spring的正常类不会扫描进去
  5. 获取到扫描的所有放入容器中的BeanDefinintion. 遍历每个BeanDefinintion并获取这个bean的第一个接口 , 并且为每一个类生成一个ServiceBean的BeanDefintion放入容器, 并且把DubboService的注解的一些信息注入ServiceBean中,第一个接口 也作为属性注入进去了, ServiceBean 是继承自ServiceConfig类的。
    生成ServiceBean的方法源码在org.apache.dubbo.config.spring.beans.factory.annotation.ServiceClassPostProcessor#buildServiceBeanDefinition 在这里, 我就不贴出来了。

到这里dubbo的Servcie的注入原理就清晰了,实际上本质还是为每个类生成了ServiceConfig 对象。

还有一个疑问就是Reference 注解是如何起作用的,这个会留在下个文章中说明。
对于dubbo的xml的整合spring的方式有疑问的可以参考

Dubbo注解方式与spring的整合原理即@DubboService的机制(2)相关推荐

  1. 【基于注解方式】Spring整合Kafka

    文章目录 1. 添加Maven依赖 2. 配置与参数分离 3. 工具类度内容 4. Producer 消息生产者配置 5. Consumer 消息消费者配置 6. 使用注解监听消息 7. 请求测试 8 ...

  2. dubbo学习(四)配置dubbo 注解方式配置

    provider service注解暴露服务 @Service public class AnnotationServiceImpl implements AnnotationService {@Ov ...

  3. 面向切面(AOP)之Spring接口方式 schema配置方式 aspectj注解方式

    一.初识AOP   关于AOP的学习可以参看帮助文档:spring-3.2.0.M2\docs\reference\html目录下index.html的相关章节      1.AOP:Aspect-O ...

  4. Spring框架(五):Spring事务简述(注解方式)

    一.Spring事务的概述 事务的作用是什么? 简单来说,就是在数据层保障一系列的数据库操作同成功同失败(提交和回滚) Spring事务作用︰在数据层或[业务层]保障一系列的数据库操作同成功同失败. ...

  5. Spring Boot整合MyBatis

    最近项目原因可能会继续开始使用MyBatis,已经习惯于spring-data的风格,再回头看xml的映射配置总觉得不是特别舒服,接口定义与映射离散在不同文件中,使得阅读起来并不是特别方便. Spri ...

  6. Spring Boot基础学习笔记07:Spring Boot整合JPA

    文章目录 零.学习目标 1.熟悉Spring Data JPA基本语法和使用 2.掌握Spring Boot与JPA的整合使用 一.Spring Data JPA概述 1.Spring Data JP ...

  7. SSH深度历险(十一) AOP原理及相关概念学习+xml配置实例(对照注解方式的优缺点)...

    接上一篇 SSH深度历险(十) AOP原理及相关概念学习+AspectJ注解方式配置spring AOP,本篇我们主要是来学习使用配置XML实现AOP 本文採用强制的CGLB代理方式 Security ...

  8. Spring教程--IOC(注解方式)和整合junit

    1 IOC装配Bean(注解方式) 1.1 Spring的注解装配Bean Spring2.5 引入使用注解去定义Bean @Component  描述Spring框架中Bean Spring的框架中 ...

  9. Spring整合Mybatis之注解方式,(注解整合Junit)

    Spring整合Mybatis之注解方式 我有一篇博客详细写了我自己使用xml的方法Spring整合MyBatis,现在我就把核心配置文件中的每个bean的配置使用注解的方式实现 注解整合MyBati ...

最新文章

  1. 计算机能力应用免考证明,青岛学信NIT认证可以免考《管理系统中计算机的应用》笔试+实践...
  2. xi mapping function-concat
  3. A.M. Deviation 思维
  4. C++ 拷贝构造函数与赋值构造函数调用时机初步01
  5. 三道小题带你了解SQL基本查询
  6. Spring : Spring Aop之ProxyFactory
  7. spring mvc和rest风格小例子
  8. [C++] C/C++ 取整函数ceil(),floor()
  9. 图片转文字,手机摇身一变就是万能扫描仪!
  10. activiti6教程四
  11. Oracle 自带管理工具
  12. antdesign vue 表格,点击某行的事件写法
  13. android键盘坏了怎么办,手机虚拟键盘失灵怎么办
  14. Matplotlib做图第一节
  15. 学习笔记——spring5概念和原理
  16. File和path的用法
  17. 谁偷了我的奶酪(上)
  18. LeedCode 172. 阶乘后的零
  19. 计算机视觉之图像检索
  20. 解决size mismatch for embedding.embed_dict.userid.weight

热门文章

  1. 硬盘挂载-硬盘挂载后为只读模式
  2. form表单提交三种方式,demo实例详解
  3. 停止抱怨的力量是多么强大-记录感受
  4. Vue_实现五星好评效果
  5. linux命令行下的tab键作用
  6. ES6 之 Promise用法详解
  7. 双重差分模型能做固定效应吗_Stata:双重差分的固定效应模型 (DID)
  8. 平安科技王健宗:所有AI前沿技术,都能在联邦学习中大展身手
  9. input输入框的事件监听
  10. log4cpp源码阅读:Appender组件学习