平安银行java面试题,源码分析Dubbo服务提供者启动流程-上篇,java消息队列面试题

Step4:尝试从BeanFactory中加载所有的注册中心,注意ServiceBean的List< RegistryConfig> registries属性,为注册中心集合。

Step5:尝试从BeanFacotry中加载一个监控中心,填充ServiceBean的MonitorConfig monitor属性,如果存在多个dubbo:monitor配置,则抛出"Duplicate monitor configs: "。

Step6:尝试从BeanFactory中加载所有的协议,注意:ServiceBean的List< ProtocolConfig> protocols是一个集合,也即一个服务可以通过多种协议暴露给消费者。

ServiceBean#afterPropertiesSet

if (getPath() == null || getPath().length() == 0) {

if (beanName != null && beanName.length() > 0 && getInterface() != null && getInterface().length() > 0 && beanName.startsWith(getInterface())) {

setPath(beanName);

}

}

Step7:设置ServiceBean的path属性,path属性存放的是dubbo:service的beanName(dubbo:service id)。

ServiceBean#afterPropertiesSet

if (!isDelay()) {

export();

}

Step8:如果为启用延迟暴露机制,则调用export暴露服务。首先看一下isDelay的实现,然后重点分析export的实现原理(服务暴露的整个实现原理)。

ServiceBean#isDelay

private boolean isDelay() {

Integer delay = getDelay();

ProviderConfig provider = getProvider();

if (delay == null && provider != null) {

delay = provider.getDelay();

}

return supportedApplicationListener && (delay == null || delay == -1);

}

如果有设置dubbo:service或dubbo:provider的属性delay,或配置delay为-1,都表示启用延迟机制,单位为毫秒,设置为-1,表示等到Spring容器初始化后再暴露服务。从这里也可以看出,Dubbo暴露服务的处理入口为ServiceBean#export—》ServiceConfig#export。

1.1 源码分析ServiceConfig#export 暴露服务

调用链:ServiceBean#afterPropertiesSet------>ServiceConfig#export

public synchronized void export() {

if (provider != null) {

if (export == null) {

export = provider.getExport();

}

if (delay == null) {

delay = provider.getDelay();

}

}

if (export != null && !export) { // @1

return;

}

if (delay != null && delay > 0) { // @2

delayExportExecutor.schedule(new Runnable() {

@Override

public void run() {

doExport();

}

}, delay, TimeUnit.MILLISECONDS);

} else {

doExport(); //@3

}

}

代码@1:判断是否暴露服务,由dubbo:service export="true|false"来指定。

代码@2:如果启用了delay机制,如果delay大于0,表示延迟多少毫秒后暴露服务,使用ScheduledExecutorService延迟调度,最终调用doExport方法。

代码@3:执行具体的暴露逻辑doExport,需要大家留意:delay=-1的处理逻辑(基于Spring事件机制触发)。

1.2 源码分析ServiceConfig#doExport暴露服务

调用链:ServiceBean#afterPropertiesSet—调用------>ServiceConfig#export------>ServiceConfig#doExport

ServiceConfig#checkDefault

private void checkDefault() {

if (provider == null) {

provider = new ProviderConfig();

}

appendProperties(provider);

}

Step1:如果dubbo:servce标签也就是ServiceBean的provider属性为空,调用appendProperties方法,填充默认属性,其具体加载顺序:

  1. 从系统属性加载对应参数值,参数键:dubbo.provider.属性名,System.getProperty。

  2. 加载属性配置文件的值。属性配置文件,可通过系统属性:dubbo.properties.file,如果该值未配置,则默认取dubbo.properties属性配置文件。

ServiceConfig#doExport

if (ref instanceof GenericService) {

interfaceClass = GenericService.class;

if (StringUtils.isEmpty(generic)) {

generic = Boolean.TRUE.toString();

}

} else {

try {

interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()

.getContextClassLoader());

} catch (ClassNotFoundException e) {

throw new IllegalStateException(e.getMessage(), e);

}

checkInterfaceAndMethods(interfaceClass, methods);

checkRef();

generic = Boolean.FALSE.toString();

}

Step2:校验ref与interface属性。如果ref是GenericService,则为dubbo的泛化实现,然后验证interface接口与ref引用的类型是否一致。

ServiceConfig#doExport

if (local != null) {

if (“true”.equals(local)) {

local = interfaceName + “Local”;

}

Class<?> localClass;

try {

localClass = ClassHelper.forNameWithThreadContextClassLoader(local);

} catch (ClassNotFoundException e) {

throw new IllegalStateException(e.getMessage(), e);

}

if (!interfaceClass.isAssignableFrom(localClass)) {

throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);

}

}

Step3:dubbo:service local机制,已经废弃,被stub属性所替换。

Step4:处理本地存根Stub,<dubbo:service 的stub属性,可以设置为true,此时Stub的类名为:interface+Stub,stub也可以指定自定义的全类名。本地存根说明如图所示(Dubbo官方文档)

这里写图片描述

ServiceConfig#doExport

checkApplication();

checkRegistry();

checkProtocol();

appendProperties(this);

Step5:校验ServiceBean的application、registry、protocol是否为空,并从系统属性(优先)、资源文件中填充其属性。

系统属性、资源文件属性的配置如下:

application dubbo.application.属性名,例如 dubbo.application.name

registry dubbo.registry.属性名,例如 dubbo.registry.address

protocol dubbo.protocol.属性名,例如 dubbo.protocol.port

service dubbo.service.属性名,例如 dubbo.service.stub

ServiceConfig#doExport

checkStubAndMock(interfaceClass);

Step6:校验stub、mock类的合理性,是否是interface的实现类。

ServiceConfig#doExport

doExportUrls();

Step7:执行doExportUrls()方法暴露服务,接下来会重点分析该方法。

ServiceConfig#doExport

ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);

ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);

Step8:将服务提供者信息注册到ApplicationModel实例中。

1.3 源码分析ServiceConfig#doExportUrls暴露服务具体实现逻辑

调用链:ServiceBean#afterPropertiesSet------>ServiceConfig#export------>ServiceConfig#doExport

private void doExportUrls() {

List registryURLs = loadRegistries(true); // @1

for (ProtocolConfig protocolConfig : protocols) {

doExportUrlsFor1Protocol(protocolConfig, registryURLs); // @2

}

}

代码@1:首先遍历ServiceBean的List< RegistryConfig> registries(所有注册中心的配置信息),然后将地址封装成URL对象,关于注册中心的所有配置属性,最终转换成url的属性(?属性名=属性值),loadRegistries(true),参数的意思:true,代表服务提供者,false:代表服务消费者,如果是服务提供者,则检测注册中心的配置,如果配置了register=“false”,则忽略该地址,如果是服务消费者,并配置了subscribe="false"则表示不从该注册中心订阅服务,故也不返回,一个注册中心URL示例:

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=7072&qos.port=22222&registry=zookeeper&timestamp=1527308268041

代码@2:然后遍历配置的所有协议,根据每个协议,向注册中心暴露服务,接下来重点分析doExportUrlsFor1Protocol方法的实现细节。

1.4 源码分析doExportUrlsFor1Protocol

调用链:ServiceBean#afterPropertiesSet------>ServiceConfig#export------>ServiceConfig#doExport------>ServiceConfig#doExportUrlsFor1Protocol

ServiceConfig#doExportUrlsFor1Protocol

String name = protocolConfig.getName();

if (name == null || name.length() == 0) {

name = “dubbo”;

}

Map<String, String> map = new HashMap<String, String>();

map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);

map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());

map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));

if (ConfigUtils.getPid() > 0) {

map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));

}

appendParameters(map, application);

appendParameters(map, module);

appendParameters(map, provider, Constants.DEFAULT_KEY);

appendParameters(map, protocolConfig);

appendParameters(map, this);

Step1:用Map存储该协议的所有配置参数,包括协议名称、dubbo版本、当前系统时间戳、进程ID、application配置、module配置、默认服务提供者参数(ProviderConfig)、协议配置、服务提供Dubbo:service的属性。

ServiceConfig#doExportUrlsFor1Protocol

if (methods != null && !methods.isEmpty()) {

for (MethodConfig method : methods) {

appendParameters(map, method, method.getName());

String retryKey = method.getName() + “.retry”;

if (map.containsKey(retryKey)) {

String retryValue = map.remove(retryKey);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

关于面试刷题也是有方法可言的,建议最好是按照专题来进行,然后由基础到高级,由浅入深来,效果会更好。当然,这些内容我也全部整理在一份pdf文档内,分成了以下几大专题:

  • Java基础部分

  • 算法与编程

  • 数据库部分

  • 流行的框架与新技术(Spring+SpringCloud+SpringCloudAlibaba)

这份面试文档当然不止这些内容,实际上像JVM、设计模式、ZK、MQ、数据结构等其他部分的面试内容均有涉及,因为文章篇幅,就不全部在这里阐述了。

作为一名程序员,阶段性的学习是必不可少的,而且需要保持一定的持续性,这次在这个阶段内,我对一些重点的知识点进行了系统的复习,一方面巩固了自己的基础,另一方面也提升了自己的知识广度和深度。

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

.(img-owFoVluN-1712507323629)]

这份面试文档当然不止这些内容,实际上像JVM、设计模式、ZK、MQ、数据结构等其他部分的面试内容均有涉及,因为文章篇幅,就不全部在这里阐述了。

作为一名程序员,阶段性的学习是必不可少的,而且需要保持一定的持续性,这次在这个阶段内,我对一些重点的知识点进行了系统的复习,一方面巩固了自己的基础,另一方面也提升了自己的知识广度和深度。

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值