dubbo:学习整理1——服务端启动流程

一,自动配置-注册相关后置处理器

1,第一种自动配置方式:

dubbo-spring-boot-autocofigure包的Spring.factories中设置了自动配置类和应用监听器的类。

在springboot启动时会自动扫描,然后进行加载对应的类并注入到容器中,需要在配置文件中配置"dubbo.scan.basePackages",

在自动配置类中com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration

直接生成ServiceAnnotationBeanPostProcessor和ReferenceAnnotationBeanPostProcessor两个bean并注册到容器中

2,第二中自动配置方式

@DubboComponentScan(basePackages="com.**.provider.service") 主类中加入这个注解

@DubboComponentScan注解会引入@Import({DubboComponentScanRegistrar.class})注册器

DubboComponentScanRegistrar什么时候会被引入?引入的作用?

1),引入时机,在ioc容器refresh()方法中,容器准备好之后调用invokeBeanFactoryPostProcessors(BeanFactory)方法,调用工厂后置处理器,其中有一个ConfigurationClassPostProcessor(很重要,ioc中被bean就是由此类加载的),就会扫描到@Import的注解,并执行registerBeanDefinitions()方法

2),registerBeanDefinitions()方法中,先找到注解的需要扫描的包packagesToScan="com.*.provider.service"

3),根据扫描包packagesToScan作为参数注入ServiceAnnotationBeanPostProcessor工厂后置处理器,服务暴露后置处理器。

4),注入ReferenceAnnotationBeanPostProcessor后置处理器,服务引用后置处理器

说明:

ServiceAnnotationBeanPostProcessor后置处理器,

是一个BeanFactoryPostProcessor在容器invokeBeanFactoryPostProcessors()过程中,会被执行。

作用:以@Service作为过滤条件,扫描指定scanBasePackages,向容器注册ServiceBean。容器在refresh()完成的时候,会向容器中发送ContextRefershEvent,ServiceBean实例会监听此事件,然后执行服务export过程,暴露服务。

 

ReferenceAnnotationBeanPostProcessor后置处理器

在容器初始化完成后,会实例化容器中的单例非懒初始化Bean。

在实例化Bean以后,初始化Bean属性前会调用populateBean()方法,执行AnnotationInjectedBeanPostProcessor为注入依赖的属性。而ReferenceAnnotationBeanPostProcessor就是继承自AnnotationInjectedBeanPostProcessor,此时它会随着一起执行。

作用:找到@Reference所注解的字段,为其注入值。

注入的值为业务接口的动态代理类,动态代理(InvocationHandler)的逻辑是调用ReferenceBean.get()方法,创建真正的Invoker。

所以最终注入了封装了远程调用逻辑的Invoker。

二,服务端启动时

AbstractApplicationContext容器refresh之后执行finishRefresh()方法中,发布事件

》》this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));

》》  SimpleApplicationEventMulticaster类中 multicastEvent()处理事情

》》this.invokeListener(listener, event)

》》 this.doInvokeListener(listener, event)

》》使用 listener.onApplicationEvent(event);

而dubbo提供者注册到容器中的bean为ServiceBean 同时是一个监听器,监听ContextRefreshedEvent事件,

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {

在ServiceBean 的onApplicationEvent(ContextRefreshedEvent event)中

》》 调用this.export();

》》转到ServiceConfig的同步方法export(),进行暴露服务,如果有延迟则延迟暴露,如果没有延迟则直接暴露服务

》》serviceConfig中doExport()检查各类参数

》》doExportUrls()方法:调用loadRegistries()方法,获取到retistryUrl列表

  》loadRegistries()方法,

调用checkRegistry()先检查是否含有<dubbo:register address=”addressname”>配置,即registries集合中是否有值,没有的话从配置文件中获取dubbo.registry.address值,构建RegistryConfig对象放入到registries集合中,如果配置文件中没有配置地址则抛出异常提醒需要配置注册地址或是将service设置为不注册。

检查完之后:

遍历registries中的每一个RegistryCongfig对象,如果配置文件配置了dubbo.registry.address的地址,则会覆盖掉registry的地址<dubbo:register address=”addressname”>即这个地址,并把配置文件中的属性放到map中去,比如应用名,dubbo版本号等用来构造url,  List<URL> urls = UrlUtils.parseURLs(address, map);构造url,因为address可能拼接了多个注册地址,所以返回URL集合,然后遍历每个url将其加入到集合List<URL> registryList中,返回registryList

遍历List<ProtocolConfig> protocols协议列表,调用this.doExportUrlsFor1Protocol(protocolConfig, registryURLs)依次注册。

》》this.doExportUrlsFor1Protocol(protocolConfig, registryURLs):使用协议信息和registryURLs注册列表作为参数。

registryURL注册地址形式如下如  注册地址可能有多个

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=providerboot_v2&dubbo=2.6.2&organization=example&owner=test&pid=12064®istry=zookeeper×tamp=1597643174790

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=providerboot_v2&dubbo=2.6.2&organization=example&owner=test&pid=12064®istry=zookeeper×tamp=1597643174790

协议的名称如果没有配置则设置为”dubbo”

将各类信息都添加到map中,如dubbo版本号,pid,各方法信息,token信息等,又拼接一个url: 此url为需要暴露的地址

dubbo://192.168.56.1:20882/com.test.serviceinterface.service.ITestService?anyhost=true&application=providerboot_v2&bind.ip=192.168.56.1&bind.port=20882&default.timeout=60000&dubbo=2.6.2&generic=false&interface=com.test.serviceinterface.service.ITestService&methods=getTest&organization=example&owner=test&pid=12064&side=provider×tamp=1597643268550

1)如果registryURLs参数不为空,说明需要注册,走的是注册的protocol(里面包含注册流程)

Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));

DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

Exporter<?> exporter = protocol.export(wrapperInvoker);

 this.exporters.add(exporter);

将url设置到registryUrl中去,作为其一个属性(暴露流程需要使用);将ref,接口信息,registryURL转为invoke,

再将invoke和serviceConfig对象 组装成wrapperInvoke,invoke和serviceConfig对象分别作为属性。

2)如果registryURLs为空,那么不需要注册,走的是暴露流程

Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, url);//这个url是需要暴露的url

DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

 Exporter<?> exporter = protocol.export(wrapperInvoker);

 this.exporters.add(exporter);

将ref,接口信息,url转为invoke,

三,暴露服务

registryURLs为空时,执行protocol.export(wrapperInvoker),wrapperInvoker中的url为需要暴露的url

serviceConfig中的静态属性protocol对象:由扩展机制可知protocol没有自适应的扩展类根据方法的@Adaptive注解生成字节码文件Protocol$Adaptive此时的protocol对象即为Protocol$Adaptive对象。

Protocol$Adaptive对象中export(invoke)方法

export()(

 com.alibaba.dubbo.common.URL url = arg0.getUrl();

   String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );

 com.alibaba.dubbo.rpc.Protocol extension =

(com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);

        return extension.export(arg0);

}

extName= url.getProtocol() 值是”dubbo”

根据扩展机制getExtension("dubbo"),最终获取到的protocol为ProtocolFilterWrapper -> ProtocolListenerWrapper -> DubboProtocol ,最后DubboProtocol .export()服务暴露服务

》》DubboProtocol的 protocol.export(wrapperInvoker)

》》this.openServer(URL url)打开服务,如果服务不存在则创建服务

》》this.createServer(URL url)

》》Exchangers.bind(url, this.requestHandler)而在headerExchanger的bind中,调用了Transporters.bind(),一直调用到NettyServer,绑定了端口和链接。

小结:每个服务绑定一个socket端口,等待调用者来调用。一个接口文件对应一个服务,如ITestService对应一个服务

ServiceBean的名称为ServiceBean:testimpl:com.**.serviceinterface.service.ITestService

拼接后的url

provider://192.168.56.1:20882/com.**.serviceinterface.service.ITestService?anyhost=true&application=providerboot_v2&category=configurators&check=false&default.timeout=60000&dubbo=2.6.2&generic=false&interface=com.test.serviceinterface.service.ITestService&methods=getTest&organization=example&owner=test&pid=15120&side=provider×tamp=1595302400861,

四,注册过程

如果registryURLs参数不为空,执行protocol.export(wrapperInvoker),wrapperInvoker中的url为需要注册的registryURL

Protocol$Adaptive对象中export(invoke)方法

extName= url.getProtocol() 值是”registry”

根据扩展机制getExtension("registry")

获取protocol的扩展类加载器,前面已经获取了,直接调用getExtension(registry)》》createExtension(String name)

registry=com.alibaba.dubbo.registry.integration.RegistryProtocol

取到com.alibaba.dubbo.registry.integration.RegistryProtocol对象,

createExtension(String name)中进行injectExtension(instance) 方法,会反射调用所有的set方法来设置属性,RegistryProtocol中的setProtocol()执行,属性protocol为之前创建的字节码文件 Protocol$Adaptive对象。然后依次实例化各个封装类,最后返回实际上是 ProtocolFilterWrapper 实例。

执.export()方法,即ProtocolFilterWrapper.export(),会依次调用 ProtocolFilterWrapper -> QosProtocolWrapper -> ProtocolListenerWrapper -> RegistryProtocol

//具体的协议去暴露服务

ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);    

      在doLocalExport(originInvoker)方法中调用this.protocol.export(invokerDelegete)

     if (exporter == null) {

                    Invoker<?> invokerDelegete = new RegistryProtocol.InvokerDelegete(originInvoker, this.getProviderUrl(originInvoker));

                    exporter = new RegistryProtocol.ExporterChangeableWrapper(this.protocol.export(invokerDelegete), originInvoker);

                    this.bounds.put(key, exporter);

                }

 private URL getProviderUrl(Invoker<?> origininvoker) {

        String export = origininvoker.getUrl().getParameterAndDecoded("export");//前面设置进去的

}

    invokerDelegete中url为需要暴露的url

    arg0值是invokerDelegete,extName= url.getProtocol() 值是”dubbo”,进入暴露过程,暴露服务。

//具体的注册中心,连接注册中心,此时提供者作为消费者引用注册中心核心服务RegistryService

 Registry registry = getRegistry(originInvoker);

//获取要注册到注册中心的url

URL registedProviderUrl = getRegistedProviderUrl(originInvoker);        

//调用远端注册中心的register方法进行服务注册,若有消费者订阅此服务,则推送消息让消费者引用此服务

registry.register(registedProviderUrl);       

//提供者向注册中心订阅所有注册服务的覆盖配置

registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);       

//返回暴露后的Exporter给上层ServiceConfig进行缓存

return new Exporter<T>() 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值