The organic combination of spring and Dubbo

1.@DubboService @DubboReference combined with Spring

Code entry: @EnableDubbo: Start the automatic configuration of dubbo. Dubbo combined with Spring entrance

Focus on: @EnableDubboConfig, @DubboComponentScan

@EnableDubboConfig

@DubboComponentScan

DubboComponentScanRegistrar, the ReferenceAnnotationBeanPostProcessor class is initialized in DubboSpringInitializer#initialize (the attribute @DubboReference injection is completed in ReferenceAnnotationBeanPostProcessor)

ReferenceAnnotationPostProcessor is initialized when initializing the dubbo bean.


In DubboComponentScanRegistrar, ServiceAnnotationPostProcessor was generated and the path to be scanned was passed in

1.1 Core principles of @DubboService

ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPostProcessor (used to dynamically generate bean information)

DubboClassPathBeanDefinitionScanner is used to scan the @DubboService annotation

1.2 Core Principles of @DubboReference

@DubboReference attribute injection is handled in ReferenceAnnotationBeanPostProcessor. After Spring instantiates the object, it will execute postProcessPropertyValues() for property injection.

1.2.1 Obtain metadata

AbstractAnnotationBeanPostProcessor

Scan the fields identified by @DubboReference in each bean object through ReflectionUtils.doWithFields

1.2.2 Inject fields identified by @DubboReference

ReferenceAnnotationBeanPostProcessor#doGetInjectedBean()

3.Dubbo xml combined with Spring

Theoretical knowledge:

  • Spring XML schema expansion mechanism: define bean objects and the relationships between bean objects through xml.
  • .xsd file: called XML schema definition. A structural language used to describe XML documents. Developed specifications for XML files. For example: define the elements and attributes of the XML document, as well as the name, data type, etc. of the attributes.
  • spring.schemas file: find the mapping relationship between schemas and xsd files
  • spring.handlers file: Find the tag parsing implementation class specified by schemas (the class that implements BeanDefinitionParser)
  • Abstract NamespaceHandler: Provides the ability to parse schemas
  • BeanDefinitionParser: Provides Element for parsing each schemas and generates specific BeanDefinition
  • BeanDefinitionParser: parses xml nodes to generate BeanDefinition.

3.1 How Dubbo implements xml configuration to generate BeanDefinition

How does Spring implement xml to generate BeanDefinition?

  1. Write an xsd file to define custom label configuration rules.
  2. The spring.schemas file defines the import form of custom tags.
  3. Implement NamespaceHandlerSupport for custom parsing logic.
  4. Write the spring.handlers file to specify the implementation class of the custom tag.

How Dubbo implements XML generation of BeanDefinition (take as an example)

  1. Write the dubbo.xsd file.
<!-- The tag name is service, the type is serviceType, and the associated complexType name=serviceType -->
<xsd:element name="service" type="serviceType">
    <xsd:annotation>
        <xsd:documentation><![CDATA[ Export service config ]]></xsd:documentation>
        <xsd:appinfo>
            <tool:annotation>
                <tool:exports type="org.apache.dubbo.config.ServiceConfig"/>
            </tool:annotation>
        </xsd:appinfo>
    </xsd:annotation>
</xsd:element>

  1. Write the spring.schemas file.
http://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd
  1. Write the spring.handlers file.
http://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
  1. Customize DubboNamespaceHandler, extends from NamespaceHandlerSupport, and resolve into ServiceBean.
    • 1. Use init() to register BeanDefinitionParser during initialization
    • 2. Complete the parsing logic in DubboNamespaceHandler‘s parse()
//DubboBeanDefinitionParser.parse()
// Note: The code for other types of Beans is removed here, only the logic of ServiceBean is retained.
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {<!-- -->
    RootBeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClass(beanClass);
    beanDefinition.setLazyInit(false);
    String id = element.getAttribute("id");
    //...omit code
    // Parse ServiceBean
    if (ServiceBean.class.equals(beanClass)) {<!-- -->
        String className = element.getAttribute("class");
        if (StringUtils.isNotEmpty(className)) {<!-- -->
            RootBeanDefinition classDefinition = new RootBeanDefinition();
            classDefinition.setBeanClass(ReflectUtils.forName(className));
            classDefinition.setLazyInit(false);
            parseProperties(element.getChildNodes(), classDefinition);
            beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
        }
    }
    //...omit code
    return beanDefinition;
}
  1. Hand over the generated Beandefinition to spring for processing

tip:

  1. spring.schemas are mapped to local files to avoid network-less situations.

Reference documentation:
@DubboService underlying mechanism
Dubbo integrates XML
Nuggets booklet provides an in-depth analysis of Dubbo architecture design and implementation principles – Chapter 6