DUBBO2.7.6源码个人理解 复制后黏贴到dubbo源码中更直观

本文详细分析了DUBBO2.7.6版本中,如何通过@Service和@Reference注解处理服务提供者和服务消费者的配置,并深入探讨了服务导出的过程,包括配置来源、服务参数、协议选择、URL构造、服务器启动以及监听服务参数变化。同时,解释了DubboBootstrap、ServiceConfig、ReferenceBean的生成及其在Spring容器中的作用。
摘要由CSDN通过智能技术生成

package org.apache.dubbo.demo.provider;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.spring.beans.factory.annotation.*;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
import org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter;
import org.apache.dubbo.rpc.Invoker;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.support.AbstractApplicationContext;

public class ProviderDoc {

/**
* 继承入spring,利用spring的@import注解
* {@link org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar }
* (实现ImportBeanDefinitionRegistrar
* 默认情况下开启了multiple模式,multiple模式表示开启多配置模式可以支持多个dubbo.protocol,比如:
* {dubbo.protocols.p1.name=dubbo
* dubbo.protocols.p1.port=20880
* dubbo.protocols.p1.host=0.0.0.0
* dubbo.protocols.p2.name=http
* dubbo.protocols.p2.port=8082
* dubbo.protocols.p2.host=0.0.0.0}
* )
* 和
* {@link org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar}
* 通过扫描进入spring容器管理 spring会调用
*
*
*
* {@link org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar#registerBeanDefinitions}
* 方法对Properties文件中的前缀、参数名、参数值生成对应的Bean进行解析
* {
* dubbo.application.name=dubbo-demo-annotation-provider dubbo.application. 生成一个ApplicationConfig类型的BeanDefinition
* dubbo.protocol.name=dubbo dubbo.protocol 生成一个ProtocolConfig类型的BeanDefinition
* dubbo.protocol.port=20880 …
* }
*
*
* {@link org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar}(扩展spring的扫描器)
* 首先获得用户指定的扫描包路径
* 然后分别生成ServiceAnnotationBeanPostProcessor和
* ReferenceAnnotationBeanPostProcessor类的BeanDefinition,并注册到Spring中,注意这两个类看上去像,但完全不是一个层面的东西。
* ServiceAnnotationBeanPostProcessor是一个BeanDefinitionRegistryPostProcessor,是在Spring扫描过程中执行的。
* ReferenceAnnotationBeanPostProcessor的父类是AnnotationInjectedBeanPostProcessor,
* 是一个InstantiationAwareBeanPostProcessorAdapter,是在Spring对容器中的bean进行依赖注入时使用的。
*
*
*{@link org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)}(扩展spring的扫描器)
* 实现spring的BeanDefinitionRegistryPostProcessor重写了postProcessBeanDefinitionRegistry(),在方法中
* 会生成一个{@link org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner}扩展了spring的扫描器,
* 扫描路径下被 {@link org.apache.dubbo.config.annotation.Service}注解的类,得到服务实现类、@Service注解信息、服务实现类实现的接口、服务实现类的beanName
* 生成一个ServiceBean对应的BeanDefinition,下面称为serviceBeanBeanDefinition,根据@Service注解上的信息对属性进行赋值
* {
* 对ref属性进行赋值(PropertyReference),赋值为服务实现类的beanName
* 对interface属性进行赋值(PropertyValue),赋值为接口名
* 对parameters属性进行赋值,把注解中的parameters属性值转化为map进行赋值
* 对methods属性进行赋值,把注解中的methods属性值转化为List进行赋值
* 如果@Service注解中配置了provider属性,则对provider属性进行赋值(PropertyReference,表示一个beanName)monitor、application、module也是类似操作
* 如果@Service注解中配置了registry属性,会对registries属性进行赋值(RuntimeBeanReference)
* 如果@Service注解中配置了protocol属性,会对protocols属性进行赋值(RuntimeBeanReference)
* }
* 总结ServiceAnnotationBeanPostProcessor主要用来扫描指定包下面的@Service注解,
* 把扫描到的@Service注解所标注的类都生成一个对应的BeanDefinition(会随着Spring的生命周期生成一个对应的Bean),
* 然后遍历扫描出来的BeanDefinition,根据@Service注解中的参数配置,会生成一个ServiceBean类型的BeanDefinition,
* 并添加到Spring容器中去,所以相当于一个@Service注解会生成两个Bean,一个当前类的Bean,一个ServiceBean类型的Bean。
* 需要注意的是ServiceBean实现了ApplicationListener接口,当Spring启动完后,会发布ContextRefreshedEvent事件,
* ServiceBean会处理该事件,调用ServiceBean的父类{@link com.alibaba.dubbo.config.ServiceConfig}中的export(),该方法就是服务导出的入口。
*
*
*
* {@link org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor}扩展AnnotationInjectedBeanPostProcessor,
* 是一个InstantiationAwareBeanPostProcessorAdapter,是在Spring对容器中的bean进行依赖注入时使用的。直观的理解就是类似于spring中的AutowiredAnnotationBeanPostProcessor类
* 其中,重写postProcessPropertyValues->findInjectionMetadata->buildAnnotatedMetadata->findFieldAnnotationMetadata被@Reference注解了的方法注入点,
* … ->findAnnotatedMethodMetadata被@Reference注解了的属性注入点,
* 调用InjectionMetadata的inject->{@link com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor
* 内部类AnnotatedMethodElement或者AnnotatedFieldElement}的重载方法findFieldAnnotationMetadata
* 方法注入method.invoke(bean, injectedObject)还是属性注入通过反射field.set(bean, injectedObject);
* 具体调用栈
* {@link org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#postProcessPropertyValues}
* -> {@link com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#InjectionMetadata#inject(Object, String, PropertyValues)->getInjectedObject()}
* ->反射
*
* @Reference 注解主要功能就将注解中的参数信息与待注入的属性类型通过被ReferenceAnnotationBeanPostProcessor扫描后生成一个ReferenceBeanName,
* 在根据参数信息与待注入的属性类型ReferenceBeanName生成ReferenceBean然后通过beanfactory注册到spring中,ReferenceBean的生产流程
* {@link org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#doGetInjectedBean}->
* {@link org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#buildReferenceBeanIfAbsent}->
* {@link ReferenceBeanBuilder#build()} ->
* {@link ReferenceBeanBuilder#doBuild() 得到一个ReferenceBean实例} ->
* {@link ReferenceBeanBuilder#configureBean 给ReferenceBean实例的属性进行赋值} ->
* {@link ReferenceBeanBuilder#preConfigureBean 把Reference注解的参数值赋值给ReferenceBean实例,除开"application", “module”, “consumer”, “monitor”, "registry"这几个参数)->
* {@link ReferenceBeanBuilder#configureRegistryConfigs、configureMonitorConfig、configureApplicationConfig、configureModuleConfig
* 对ReferenceBean实例的registries、Monitor、Application、Module属性进行赋值,通过@Reference注解中所配置的属性获得到值,然后根据该值从Spring容器中获得到bean}->
* {@link ReferenceBeanBuilder#postConfigureBean 对applicationContext、interfaceName、consumer、methods属性进行赋值}
* 最后调用ReferenceBean实例的afterPropertiesSet方法,调用ReferenceBean的get方法得到一个接口的代理对象,最终会把这个代理对象注入到属性中去
*
*
*服务导出,dubbo的DubboBootstrapApplicationListener继承OneTimeExecutionApplicationContextEventListener,
* OneTimeExecutionApplicationContextEventListener实现spring的ApplicationListener, ApplicationContextAware扩展两个接口
* 在这其中ApplicationListener类的onApplicationEvent在spring{@link AbstractApplicationContext#refresh() - {@link AbstractApplicationContext#finishRefresh()}}方法中调用
* {@link org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener 重写onApplicationContextEvent方法}->
* {@link org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener#onContextRefreshedEvent{ dubboBootstrap.start()} }
* {@link org.apache.dubbo.config.bootstrap.DubboBootstrap#start}->
* {@link org.apache.dubbo.config.bootstrap.DubboBootstrap#exportServices}
* {@link com.alibaba.dubbo.config.ServiceConfig#export() }在执行这个方法时已经有一些@Service注解上定义的参数了
* 例:<dubbo:service beanName=“ServiceBean:org.apache.dubbo.demo.DemoService:d1” />这里d1就是注解上的group属性
* 但是在Dubbo中,除开可以在@Service注解中给服务配置参数,还有很多地方也可以给服务配置参数,比如:
* 1. dubbo.properties文件,你可以建立这个文件,dubbo会去读取这个文件的内容作为服务的参数,Dubob的源码中叫做PropertiesConfiguration
* 2. 配置中心,dubbo在2.7版本后就支持了分布式配置中心,你可以在Dubbo-Admin中去操作配置中心,分布式配置中心就相当于一个远程的dubbo.properties文件,
* 你可以在Dubbo-Admin中去修改这个dubbo.properties文件,当然配置中心支持按应用进行配置,也可以按全局进行配置两种,在Dubbo的源码中AppExternalConfiguration表示应用配置,
* ExternalConfiguration表示全局配置。
* 3. 系统环境变量,你可以在启动应用程序时,通过-D的方式来指定参数,在Dubbo的源码中叫SystemConfiguration
* 4. 再加上通过@Service注解所配置的参数,在Dubbo的源码中叫AbstractConfig
*
* 服务的参数可以从这四个位置来,这四个位置上如果配了同一个参数的话,优先级从高到低如下:
* SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
* -D方式配置的参数优先级最高,配置中心次之, 注解随后, dubbo.properties最后。
* 先从上级获取参数,获取之后,如果服务本身配置了相同的参数,那么则进行覆盖。
*
* 导出的几件事
* 1. 确定服务的参数
* 2. 确定服务支持的协议
* 3. 构造服务最终的URL
* 4. 将服务URL注册到注册中心去
* 5. 根据服务支持的不同协议,启动不同的Server,用来接收和处理请求
* 6. 因为Dubbo支持动态配置服务参数,所以服务导出时还需要绑定一个监听器Listener来监听服务的参数是否有修改,如果发现有修改,则需要重新进行导出
*
*
* 由export方法开始紧接着 Protocol默认使用dubbo当然dubbo支持http,rmi,grpc,thrift,websocket、Hessian等协议
* {@link org.apache.dubbo.config.ServiceConfig#doExport() }->
* {@link org.apache.dubbo.config.ServiceConfig#doExportUrls() }->
* {@link org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol 有了确定的协议,服务名,服务参数后,组装成服务的URL}->
* {@link org.apache.dubbo.demo.provider.proxy.ProtocolKaTeX parse error: Expected 'EOF', got '#' at position 9: Adaptive#̲export 这个是我使用du…Adaptive#export 使用dubbo代理生成的类返回ProtocolFilterWrapper}->
* (
* 这里获取AbstractProtocol的继承类,根据配置不同,例如demo中配置dubbo.protocol.name=dubbo那就是DubboProtocol
* AbstractProxyProtocol
* DubboProtocol
* GrpcProtocol
* HessianProtocol
* HttpProtocol
* InjvmProtocol
* MemcachedProtocol
* MockProtocol
* RedisProtocol
* RestProtocol
* RmiProtocol
* ThriftProtocol
* ThriftProtocol
* WebServiceProtocol
* XmlRpcProtocol
* )
* {@link org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#export}->
* {@link org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer 启动netty}->
* {@link org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer} ->
* {@link org.apache.dubbo.remoting.exchange.Exchangers#bind(URL url, ExchangeHandler requestHandler 用来处理请求
* 在dubboprotocol中ExchangeHandler是一个接口实现 private ExchangeHandler requestHandler = new ExchangeHandlerAdapter () {}
* )根据url得到一个默认的HeaderExchange,HeaderExchanger中包括HeaderExchangeClient(发送心跳)、HeaderExchangeServer(接收心跳)}->
* {@link org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger#bind 返回ExchangeServer}->
* {@link org.apache.dubbo.remoting.Transporters#bind(URL, ChannelHandler…) ;
* 这个方法中调用了getTransporter(这是dubbo的spi扩展 ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension())
* 默认情况下通过javasist代理的Transporter$Adaptive类的bind放返回一个NettyTransporter
* 实际源码中这里根据配置不同可以获取到不同的Transporter的实现类默认netty
* GrizzlyTransporter
* MinaTransporter
* NettyTransporter
* NettyTransporter(netty4)
* }->
* {@link org.apache.dubbo.remoting.transport.netty4.NettyTransporter#bind(URL, ChannelHandler) 方法得到一个Serve,同样默认server是NettyServer}
* {@link org.apache.dubbo.remoting.transport.netty4.NettyServer#NettyServer 跳转连接查看具体方法体注释}
* 同样的根据配置不同可以获取到不同的Transporter的实现类默认netty
* GrizzlyServer
* GrpcRemotingServer
* HeaderExchangeServer
* HttpServer
* JettyHttpServer
* MinaServer
* NettyServer
* NettyServer
* Peer
* RemotingServerAdapter
* Server
* ServerDelegate
* ServerPeer
* ServletHttpServer
* TomcatHttpServer
* 示例:{@link org.apache.dubbo.demo.provider.Application.ProviderConfiguration 放入
* @Bean
* public ProtocolConfig protocolConfig(){
* ProtocolConfig protocolConfig = new ProtocolConfig();
* protocolConfig.setName(“http”);
* protocolConfig.setServer(“tomcat”);
* return protocolConfig;
* }
*
* }->
*url注册到zookeeper示例
* dubbo://192.168.1.100:20880/org.apache.dubbo.demo.DemoService?anyhost=true&
* application=dubbo-demo-annotation-provider&cluster=failback&deprecated=false&
* dubbo=&dynamic=true&generic=false&group=d1&interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&
* pid=25104&release=2.7.6&side=provider&timestamp=1602645514456
**/
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值