Dubbo系列讲解之服务注册【3万字长文分享】,阿里面试100题

本文深入剖析了Dubbo服务注册的整个过程,从ServiceAnnotationBeanPostProcessor构造方法开始,详细讲解了扫描、注册、BeanDefinition的构建,以及ServiceBean的生成和命名规则。通过源码分析,揭示了ServiceBean如何通过SPI机制与其他组件交互,最终完成服务的发布。此外,文章还介绍了服务发布的关键步骤,包括Invoker的生成、动态代理的实现和协议的自适应扩展。适合对Dubbo感兴趣的开发者深入理解服务注册机制。
摘要由CSDN通过智能技术生成

首先进入构造方法

public ServiceAnnotationBeanPostProcessor(Set packagesToScan) {

super(packagesToScan);

}

这里将传入的packagesToScan往父类进行传递,由于它继承了ServiceClassPostProcessor,现在进入ServiceClassPostProcessor类的构造方法:

public ServiceClassPostProcessor(Set packagesToScan) {

this.packagesToScan = packagesToScan;

}

ServiceClassPostProcessor只是将传入的扫包路径赋值给packagesToScan

根据BeanPostProcessor的特性,现在进入到postProcessBeanDefinitionRegistry方法

@Override

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

// @since 2.7.5

registerBeans(registry, DubboBootstrapApplicationListener.class);

Set resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {

registerServiceBeans(resolvedPackagesToScan, registry);

} else {

if (logger.isWarnEnabled()) {

logger.warn(“packagesToScan is empty , ServiceBean registry will be ignored!”);

}

}

}

该方法主要做了以下几件事:

  • 注册了一个DubboBootstrapApplicationListener监听,具体作用稍后再叙

  • 调用resolvePackagesToScan方法解析所有包名的路径。可能包名中存在一Placeholders的特殊定义

  • 调用registerServiceBeans方法进行注册

具体怎么解析包路径不在本次讨论范围,所有就先不深入了,现在直接进入到registerServiceBeans方法中

private void registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) {

DubboClassPathBeanDefinitionScanner scanner =

new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);

BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);

scanner.setBeanNameGenerator(beanNameGenerator);

// refactor @since 2.7.7

serviceAnnotationTypes.forEach(annotationType -> {

scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));

});

for (String packageToScan : packagesToScan) {

// Registers @Service Bean first

scanner.scan(packageToScan);

// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.

Set beanDefinitionHolders =

findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {

for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {

registerServiceBean(beanDefinitionHolder, registry, scanner);

}

if (logger.isInfoEnabled()) {

logger.info(beanDefinitionHolders.size() + " annotated Dubbo’s @Service Components { " +

beanDefinitionHolders +

" } were scanned under package[" + packageToScan + “]”);

}

} else {

if (logger.isWarnEnabled()) {

logger.warn(“No Spring Bean annotating Dubbo’s @Service was found under package[”

  • packageToScan + “]”);

}

}

}

}

该方法有主要做了以下几件事

  • 构建了一个DubboClassPathBeanDefinitionScanner对象,该对象继承自Spring的ClassPathBeanDefinitionScanner。在Spring中,ClassPathBeanDefinitionScanner是一个扫描程序,主要用来扫描Classpath下符合条件的对象,然后将对象注入到给定的registry中

  • 定义一个为Bean生成名称的BeanNameGenerator,这里生成的是AnnotationBeanNameGenerator这个策略

  • 将bean名称策略set到scanner中

  • 添加过滤Filter,这里遍历serviceAnnotationTypes,获取到所有的过滤条件,这里是基于注解的拦截,到serviceAnnotationTypes赋值的地方,可以看到。初始化了以下三种注解作为拦截

private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(

// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007

DubboService.class,

// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service

Service.class,

// @since 2.7.3 Add the compatibility for legacy Dubbo’s @Service , the issue : https://github.com/apache/dubbo/issues/4330

com.alibaba.dubbo.config.annotation.Service.class

);

  • 遍历解析后的扫描的包,调用scanner.scan(packageToScan)注册所有标注了@Service的bean注入到ioc容器中

  • 调用findServiceBeanDefinitionHolders查找所有标注了@Service的Class封装成BeanDefinitionHolders,不管是否被@ComponentScan扫描

  • 如果beanDefinitionHolders存在元素,遍历beanDefinitionHolders,调用registerServiceBean注册

将标注了@Service注解的bean注入到ioc容器不属于本次讨论内容,这里也不做详细说明

下面进入到findServiceBeanDefinitionHolders方法,了解一下该方法都返回了那些类型的BeanDefinitionHolder

private Set findServiceBeanDefinitionHolders(

ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry,

BeanNameGenerator beanNameGenerator) {

Set beanDefinitions = scanner.findCandidateComponents(packageToScan);

Set beanDefinitionHolders = new LinkedHashSet<>(beanDefinitions.size());

for (BeanDefinition beanDefinition : beanDefinitions) {

String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);

BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);

beanDefinitionHolders.add(beanDefinitionHolder);

}

return beanDefinitionHolders;

}

  • 首先扫描传入的packageToScan包下的所有的符合在scanner中定义的过滤注解的.class文件,封装成BeanDefinition

  • 遍历扫描到的beanDefinitions,通过名称策略,为Bean生成名称,同时用Bean和名称构建成BeanDefinitionHolder,加入到beanDefinitionHolders中,返回该集合

beanDefinitionHolders

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值