At the beginning

Dubbo is typically used with Spring integration, an excellent open source framework that provides many extension points for third-party frameworks to integrate with. After all, spring and Dubbo integration means that many objects in Dubbo are managed by Spring, such as configuration classes, protocols, etc. Before understanding integration, you need to have a clear understanding of dubbo’s SPI mechanism in the previous section, and you need to have some understanding of Spring’s source code, such as Spring beanDefiniton, extension points, etc., otherwise the code will look confused

To streamline the process

The Dubbo and Spring integration does three main things

1. Parse the configuration file into a Dubbo bean to generate a beanDefinition that meets Spring conditions

2.@DubboComponentScan package scan to process @service and @Reference annotations in the customized package path

3. Handle the Dubbo server @service annotation

4. Handle @Reference annotations on the Dubbo consumer

5. Service export (it belongs to the listening time after the Spring container is started, which will be written in a separate chapter later)

Source process

Address: www.processon.com/view/link/6…

Parsing configuration files

Dubbo total integrated spring entrance for @ EnableDubbo, then click enter @ EnableDubboConfig, see @ Import into a DubboConfigConfigurationRegistrar class, The import annotation indicates that the class is loaded when the configuration file is loaded

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @EnableDubboConfig @DubboComponentScan public @interface EnableDubbo { } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @Import(DubboConfigConfigurationRegistrar.class) public @interface EnableDubboConfig { /** * It * * @return the default value is <code>false</code> * @revised 2.5.9  */ boolean multiple() default true; }Copy the code

Here is an important method, registerBeans (registry, DubboConfigConfiguration. Single. Class); The DubboConfigConfiguration class is important

@EnableDubboConfigBindings({
            @EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
            @EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
    })
Copy the code

EnableDubboConfigBinding this annotation at boot time loads DubboConfigBindingRegistrar, this class implements a ImportBeanDefinitionRegistrar interface, This interface is an extension point provided by Spring. Implementing this interface invokes the custom registerBeanDefinitions interface for customizing beanDefinitions. RegisterDubboConfigBeans starts parsing the configuration files, such as // dubo.protocols.p1.port=20880, which will eventually translate all the configuration files into Spring’s beanDefinition object

@ DubboComponentScan package scans

Set in the @ EnableDubbo annotation @ DubboComponentScan annotations, @ Import DubboComponentScanRegistrar Import the launch configuration class. The process for @ EnableDubbo – > @ DubboComponentScan – > DubboComponentScanRegistrar – > registerServiceAnnotationBeanPostProcessor @ Service annotations (registration) – > registerReferenceAnnotationBeanPostProcessor ((registered @ Reference annotation))

@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {System. Out. Println (" executive DubboComponentScanRegistrar "); Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); / / processing service annotations registerServiceAnnotationBeanPostProcessor (packagesToScan, registry); / / processing reference annotation registerReferenceAnnotationBeanPostProcessor (registry); }Copy the code

Parse the @service annotation

On the server side, if you want to provide your own interface to consumers for remote calls, add the @Service annotation to the interface implementation class. The @Service annotation is different from the @Service annotation in Spring. Dubbo’s @Service annotation exports the corresponding bean as a Dubbo Service. Looking back, registerServiceAnnotationBeanPostProcessor 1 could be completed in a total of three things. Generate the plain beanDefiniton required by Spring, such as DemoServiceImpl 2. Generate a Dubbo ServiceBean that is important enough for future service exports to depend on 3. ServiceBean registers to listen for spring container startup events. After spring startup is complete, serviceBean.onEvent is called to export the service

@service source code parsing

1. Registered ServiceAnnotationBeanPostProcessor, due to the interface implementation BeanDefinitionRegistryPostProcessor, So the spring start calling ServiceAnnotationBeanPostProcessor. PostProcessBeanDefinitionRegistry 2. RegisterServiceBeans scan packages, for common Bean registration, Scan for class 3 annotated by the Service annotation. Registered ServiceBean, see ServiceAnnotationBeanPostProcessor buildServiceBeanDefinition ServiceBean has a lot of important attributes, Such as ref – the service implementation class, the protocol agreement, interfaceName interface name, applicationEventPublisher spring listener

private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) {/ / @ Service annotations the Annotation Service = findServiceAnnotation (beanClass); / / @ information Service annotations on AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes (Service, false, false); / / generates a ServiceBean AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition (service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName); }Copy the code

4. The serviceBean listens for spring startup events to export services

@Override public void onApplicationEvent(ContextRefreshedEvent event) { if (! isExported() && ! isUnexported()) { if (logger.isInfoEnabled()) { logger.info("The service ready on spring started. service: " + getInterface()); } // Export (); }}Copy the code

Parse @Reference annotations

On the consumer side, if you want to remotely invoke the interface provided by the service provider, add @Reference to the invoked interface. Looking back, registerReferenceAnnotationBeanPostProcessor could be completed in a total of three things, and @ are similar to the Service

1. Generate the referenceBean object

2. Generate service interface proxy objects

@reference source code parsing

1. Registered ReferenceAnnotationBeanPostProcessor, inherited the spring BeanPostProcessor 2. The callback time: spring dependency injection, call AnnotationInjectedBeanPostProcessor. PostProcessPropertyValues

@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {// Find the attribute to be injected (Field annotated by @reference) InjectionMetadata Metadata = findInjectionMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName() + " dependencies is failed", ex); } return pvs; }Copy the code

3. Look for injection point, 2 step findInjectionMetadata. BuildAnnotatedMetadata

4. Find after injection point, use the new AnnotationInjectedBeanPostProcessor. AnnotatedInjectionMetadata injection

5. Called the injected AnnotatedInjectionMetadata. Inject

6. Call ReferenceAnnotationBeanPostProcessor. DoGetInjectedBean

Two things are done here: 1. Generate the referencedBean proxy object 2. Register the beanName in the referencedBean with the Spring container, such as demoServiceImpl

Generate the referencedBean proxy object, which is separate from the referencedBean. GetOrCreateProxy is an important method called here, which will be used as the entrance to the service introduction, that is, how to call the consumer from the registry to the server

private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, ReferenceBean referenceBean, Class<? > serviceInterfaceType) { if (existsServiceBean(referencedBeanName)) { // If the local @Service Bean exists, build a proxy of ReferenceBean return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType}, wrapInvocationHandler(referenceBeanName, referenceBean)); } else {// ReferenceBean should be initialized and get immediately // ReferenceBean. }}Copy the code

ReferenceBean has several important properties: 1. REF_PROTOCOL agreement, SPI mechanism private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

  1. PROXY_FACTORY proxy factory, which will generate proxy objects for many services, dubbo proxy objects later

private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

conclusion

Dubbo’s core source code has not yet appeared, such as how to register the service export, how to import, how to call, will be written separately later