dubbo系列之@Service注解解析原理(四)
欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系
前言
前面几篇文章,讲的是调试环境搭建,配置解析读取,本文讲的是dubbo如何解析@service注解的,了解这些东西对于真正使用dubbo来说,没有直接的东西,但是这个是我后面要写的dubbo核心功能源码解析的前提,前后连贯,这样才能了解的更加清晰一点。
解析入口
@service注解解析入口有两个地方,二者是二选一的
第一种
DubboAutoConfiguration 这个自动配置类中
@ConditionalOnMissingBean
@Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)
public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
return new ReferenceAnnotationBeanPostProcessor();
}
@ConditionalOnProperty(name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnClass(RelaxedPropertyResolver.class)
@Bean
public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(Environment environment) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment);
Set<String> packagesToScan = resolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
return new ServiceAnnotationBeanPostProcessor(packagesToScan);
}
上面两个配置的作用,在上文中已经讲解过,此处不再赘述
第二种
@SpringBootApplication
@DubboComponentScan("com.dubbo.consumer.service")
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
请求头上使用了@DubboComponentScan 注解,该注解是导入一个DubboComponentScanRegistrar这个类。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
DubboComponentScanRegistrar是一个实现了ImportBeanDefinitionRegistrar 接口的类,主要看registerBeanDefinitions 方法,该方法会实例化一些BeanDefinition进入spring容器
Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取扫描包路径
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 注册@service解析的类
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 注册解析@Reference注解的bean
registerReferenceAnnotationBeanPostProcessor(registry);
}
在我们的调试例子中,使用的是在启动类中添加注解进行@DubboComponentScan 启动的,所以这里就按照这个方式来,其实第一种和第二种的方式是差不多的,最终都是通过初始化ServiceAnnotationBeanPostProcessor 这个类来达到解析@Service 并生成bean的目的。 接着上面的代码讲,注册解析@@service的方法是
registerServiceAnnotationBeanPostProcessor , 下面看一下这个方法。
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 构建ServiceAnnotationBeanPostProcessor的 BeanDefinitionBuilder
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
builder.addConstructorArgValue(packagesToScan); // 扫描的包
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 创建BeanDefinition并注册到容器中。
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
这个方法就是这么简单,有些朋友可能觉得,就这几行代码,就能够解析@Service注解了? 完全没有看到解析的逻辑代码呢。其实主要的在于ServiceAnnotationBeanPostProcessor 这个类。
ServiceAnnotationBeanPostProcessor
public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
ResourceLoaderAware, BeanClassLoaderAware {
// 代码省略
}
首先我们看一下这个类他实现的接口,实现了BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware这四个接口, 主要看BeanDefinitionRegistryPostProcessor这个接口,看一下下面的官方解释
**官方解释 **
允许在正常的BeanFactoryPostProcessor检测开始之前注册更多的自定义bean。特别是,BeanDefinitionRegistryPostProcessor
可以注册更多的bean定义,然后定义BeanFactoryPostProcessor实例。也就是说可以借此方法实现自定义的bean,通过重写postProcessBeanDefinitionRegistry方法来自定义bean
通过看上面的解释,我们直接找到postProcessBeanDefinitionRegistry方法
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 获取扫描包,扫描包可以是多个,所以这里使用了Set集合
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
// 判断需要扫描的包是否为空
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
// 不为空则调用方法进行解析
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
registerServiceBeans
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 定义扫描对象,该类继承了ClassPathBeanDefinitionScanner类
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
// beanName解析器
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// 这行代码很重要,添加了过滤器, 一个注解过滤器,用来过滤出来写了@Service注解的对象
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
// 扫描正式开始,遍历包
for (String packageToScan : packagesToScan) {
// Registers @Service Bean first
scanner.scan(packageToScan);
// 开始查找添加了@Service注解的类
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
// 找到了则不为空
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
// 循环。
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
// 注册serviceBean
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 + "]");
}
}
}
}
上面的代码,主要作用就是通过扫描过滤器,扫描包中添加了@Service注解的类。最后得到BeanDefinitionHolder对象,调用registerServiceBean来注册ServiceBean
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
// 服务接口类对象
Class<?> beanClass = resolveClass(beanDefinitionHolder);
// 找到@service注解
Service service = findAnnotation(beanClass, Service.class);
// 接口服务的实现类对象
Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service);
// 得到bean的名称
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// 构建ServiceBean对象的BeanDefinition,通过Service注解对象,以及接口服务的实现类生成ServiceBean
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);
// 构建ServuceBean的名称
String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName);
// 校验Bean是否重复
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
// 调用BeanDefinitionRegistry注册。
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
if (logger.isInfoEnabled()) {
logger.warn("The BeanDefinition[" + serviceBeanDefinition +
"] of ServiceBean has been registered with name : " + beanName);
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition +
"] of ServiceBean[ bean name : " + beanName +
"] was be found , Did @DubboComponentScan scan to same package in many times?");
}
}
}
buildServiceBeanDefinition这个方法用来构建ServiceBean对象,每个暴露出的服务,最终都会构建成一个ServiceBean,
private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass,
String annotatedServiceBeanName) {
// 生成ServiceBean对象BeanDefinitionBuilder
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
// 获取beanDefinition
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 属性集合
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
// 忽略的属性,指的是AnnotationPropertyValuesAdapter中,不把以下属性放到PropertyValues中去
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface");
//
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames));
// 设置ref属性
addPropertyReference(builder, "ref", annotatedServiceBeanName);
// 服务的接口
builder.addPropertyValue("interface", interfaceClass.getName());
/**
* 获取注解中的provider属性
*/
String providerConfigBeanName = service.provider();
if (StringUtils.hasText(providerConfigBeanName)) {
addPropertyReference(builder, "provider", providerConfigBeanName);
}
/**
* 获取注解中的monitor属性
*/
String monitorConfigBeanName = service.monitor();
if (StringUtils.hasText(monitorConfigBeanName)) {
addPropertyReference(builder, "monitor", monitorConfigBeanName);
}
/**
* 获取注解中的application属性
*/
String applicationConfigBeanName = service.application();
if (StringUtils.hasText(applicationConfigBeanName)) {
addPropertyReference(builder, "application", applicationConfigBeanName);
}
/**
* 获取注解中的模块属性
*/
String moduleConfigBeanName = service.module();
if (StringUtils.hasText(moduleConfigBeanName)) {
addPropertyReference(builder, "module", moduleConfigBeanName);
}
/**
* 获取注解中的注册中心属性
*/
String[] registryConfigBeanNames = service.registry();
List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
if (!registryRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("registries", registryRuntimeBeanReferences);
}
/**
* 获取注解中的协议属性
*/
String[] protocolConfigBeanNames = service.protocol();
List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
if (!protocolRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
}
return builder.getBeanDefinition();
}
最终dubbo解析出了ServiceBean对象的beandefinition放入了spring的容器。ServiceBean对于每个暴露的服务来说很重要,每个暴露的服务都拥有一个ServiceBean,这个类里面包含了服务发布,服务下线等操作,算是一个很核心的类,后面会讲到。
欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系