zoukankan      html  css  js  c++  java
  • dubbo @service @dubboService解析

    老规矩,从框架的使用方式入手分析,类似mybatis,dubbo也有个扫描服务的注解:org.apache.dubbo.config.spring.context.annotation.DubboComponentScan

    同样地,配套一个@Import:org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar,作用就是把BeanDefinitionRegistry交给你全权处理,

    对应这里就是构建一个org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor的BeanDefinition,然后加入BeanDefinitionRegistry。

    这是个BeanDefinitionRegistry后处理bean,主要逻辑在父类org.apache.dubbo.config.spring.beans.factory.annotation.ServiceClassPostProcessor,最新版本直接就用了父类。

    在如下dubbo springboot自动配置包中有个自动配置类,也是通过该后置bean解析@dubboService类的,不同的是,该自动配置的方式是从yaml获取服务类所在的包路径:

     自动配置类org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration:

     

     对应yaml文件内容如下,这种方式配置的好处是可以把该配置项放到配置中心统一管理:

    下面我们具体看下这个类:

    实现了接口BeanDefinitionRegistryPostProcessor,对BeanDefinitionRegistry进行后处理,主要逻辑在org.apache.dubbo.config.spring.beans.factory.annotation.ServiceClassPostProcessor#registerServiceBeans方法:

    private void registerServiceBeans(Set<String> 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 -> {
    // 设置扫描的包下被指定注解标注的类是需要处理的serviceAnnotationTypes包含如下几个注解
    // org.apache.dubbo.config.annotation.DubboService,2.7.7版本后直接用这个注解暴露服务
    // org.apache.dubbo.config.annotation.Service,@Deprecated
    // com.alibaba.dubbo.config.annotation.Service,@Deprecated scanner.addIncludeFilter(
    new AnnotationTypeFilter(annotationType)); }); for (String packageToScan : packagesToScan) { // 注册注解标注的类BeanDefinition // Registers @Service Bean first scanner.scan(packageToScan); // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not. Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator); if (!CollectionUtils.isEmpty(beanDefinitionHolders)) { for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
    // 构建org.apache.dubbo.config.spring.ServiceBean对应的BeanDefinition并注册到BeandefinitionRegistry 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 + "]"); } } } }

     重点看下注册ServiceBean代码:

    private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                         DubboClassPathBeanDefinitionScanner scanner) {
    
            Class<?> beanClass = resolveClass(beanDefinitionHolder);
    
            Annotation service = findServiceAnnotation(beanClass);
    
            /**
             * The {@link AnnotationAttributes} of @Service annotation
             */
            AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
         // 服务接口类,可通过@DubboService的interfaceClass或者interfaceName指定,默认为注解标注类对应的接口class
            Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
    
            String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
            // 构建ServiceBean的BeanDefinition用于注册
            AbstractBeanDefinition serviceBeanDefinition =
                    buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
    
            // ServiceBean Bean name
            String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
    
            if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
    // 注册ServiceBean的BeanDefinition
    registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { logger.info("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?"); } } }
    private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
                                                                  AnnotationAttributes serviceAnnotationAttributes,
                                                                  Class<?> interfaceClass,
                                                                  String annotatedServiceBeanName) {
    
            BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
    
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    
            MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
    
            String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
                    "interface", "interfaceName", "parameters");
    
            propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
    
            // References "ref" property to annotated-@Service Bean
    // 指向标注@DubboService注解的原始Bean(在服务暴露的时候会用到)
    addPropertyReference(builder, "ref", annotatedServiceBeanName); // Set interface
    // 指向@DubboService配置的服务接口类名,默认为标注类的接口类(在服务暴露的时候会用到
    builder.addPropertyValue("interface", interfaceClass.getName()); // Convert parameters into map builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters"))); // Add methods parameters List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods")); if (!methodConfigs.isEmpty()) { builder.addPropertyValue("methods", methodConfigs); } /** * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference */ String providerConfigBeanName = serviceAnnotationAttributes.getString("provider"); if (StringUtils.hasText(providerConfigBeanName)) { addPropertyReference(builder, "provider", providerConfigBeanName); } /** * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference */ String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor"); if (StringUtils.hasText(monitorConfigBeanName)) { addPropertyReference(builder, "monitor", monitorConfigBeanName); } /** * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference */ String applicationConfigBeanName = serviceAnnotationAttributes.getString("application"); if (StringUtils.hasText(applicationConfigBeanName)) { addPropertyReference(builder, "application", applicationConfigBeanName); } /** * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference */ String moduleConfigBeanName = serviceAnnotationAttributes.getString("module"); if (StringUtils.hasText(moduleConfigBeanName)) { addPropertyReference(builder, "module", moduleConfigBeanName); } /** * Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference */ String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry"); List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames); if (!registryRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("registries", registryRuntimeBeanReferences); } /** * Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference */ String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol"); List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames); if (!protocolRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); } return builder.getBeanDefinition(); }
  • 相关阅读:
    java内存管理的一些基础,内存溢出的解决方案
    设计模式中类的关系 .
    一个很郁闷的问题,Java中的僵死进程
    quartzscheduler的集群化配置
    转 : 敏捷开发的原则 .
    如何进行单元测试
    欢迎来到地狱 WriteUp(2019暑假CTF第一周misc)
    20181218小黄衫获得感想和阶段性总结
    2019暑假Java学习笔记(一)
    2019“嘉韦思杯”3.30初赛一部分Write Up
  • 原文地址:https://www.cnblogs.com/reboot30/p/15089318.html
Copyright © 2011-2022 走看看