1. Introduction

Thanks to Spring’s “microkernels and extensions mechanism,” third-party frameworks can easily integrate with Spring.

In this note, we look at “Dubbo’s process for exporting services through Spring “to see how Spring integrates with third-party frameworks and what extension points Spring provides.

Related component versions:

		<parent>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-parent</artifactId>
                        <version>2.4.0</version>
                        <relativePath/> <! -- lookup parent from repository -->
		</parent>
		<! -- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo -->
		<dependency>
			<groupId>org.apache.dubbo</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.7.3</version>
		</dependency>


		<! -- https://mvnrepository.com/artifact/com.101tec/zkclient -->
		<! -- Compatibility issues with 0.11 -->
		<dependency>
			<groupId>com.101tec</groupId>
			<artifactId>zkclient</artifactId>
			<version>0.10</version>
		</dependency>

		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-recipes</artifactId>
			<version>4.2.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.apache.zookeeper</groupId>
					<artifactId>zookeeper</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
Copy the code

2.ServiceBean.class

The Dubbo export service entry method is the onApplicationEvent method of ServiceBean.

ServiceBean encapsulates each dubbo service, such as the following Dubbo Provider configuration file:


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">


<! -- Provider application information for calculating dependencies -->
    <dubbo:application name="hello-world-app"  />

    <! Use zK Broadcast Registry to expose service address -->
    <dubbo:registry address=Zookeeper: / / "127.0.0.1:2181" />

    <! Expose service on port 20880 with dubbo
    <dubbo:protocol name="dubbo" port="20880" />

    <! Declare the service interface to be exposed -->
    <dubbo:service interface="com.huang.dubbo.api.DemoService" ref="demoServiceImpl" />

<! -- &lt; ! &ndash; Implement services as local beans. &gt; -->
<! -- <bean id="demoService" class="com.huang.dubboprovider.service.DemoServiceImpl" />-->
</beans>			
Copy the code

“” dubbo: service interface =” com. Huang. Dubbo. API. DemoService “ref =” demoServiceImpl “/ >” in the end will be encapsulated into a ServiceBean.

The onApplicationEvent method is a ServiceBean implemented in the ApplicationListener interface, which is a Spring bean extension point that implements this interface. The ability to subscribe to specified events from the Spring container, and when Spring broadcasts the specified event, the corresponding Spring bean can call the onApplicationEvent method to execute its planned logic.

We start the Spring project with a breakpoint on the ServiceBean onApplicationEvent method. As you can see from the call stack, the Spring container calls the refreshContext method during startup, which performs a lot of key logic that is not covered in this note. As long as we know that after Spring has executed refreshContext (finishRefresh), the Spring container will broadcast a ContextRefreshedEvent event, and ServiceBean will subscribe to this event and execute the corresponding logic. This is actually an implementation of the observer pattern. Spring uses the observer pattern to let third-party frameworks interact with the Spring container through specified events. Finally, ServiceBean calls the export() method to register the corresponding Dubbo service with the registry.

Spring applications inherit events from ApplicationEvents. In addition to ContextRefreshedEvent, there are many other events that can be listened to. Developers can subscribe to these events in the Spring application lifecycle as needed. To interact with Spring without modifying Spring code. This is the beauty of Spring’s extension mechanism XD.

3. The Spring container creates the ServiceBean process

As we know from Chapter 2 above, the Dubbo service is exported via ServiceBean and registered to a specified registry. This is an “effect”, but we need to clarify the “cause”. What is cause? How the Spring container reads the configuration from Dubbo’s provider.xml file and creates the corresponding ServiceBean instance is the “cause”. Knowing this, we can say “I know how Dubbo integrates with Spring! “.

The service configuration that Dubbo exposes is in the provider.xml file. (Dubbo also provides a way to configure the service in Java code, which is not covered in this note.) . As we all know, In addition to being able to configure and create beans through code annotations,Spring can also configure beans through XML files and have the Spring container read the XML files to create beans. Dubbo :service/ dubbo:service/ dubbo:service/ dubbo:service/ This is the Spring XML Schema-based configuration mechanism, which makes bean configuration files more generic and convenient. Users can define their own XML tags and validate them against custom XSD files. The Spring container does not recognize user-defined tags when reading them, so you need to implement NamespaceHandler and BeanDefinitionParser for your custom XML files to parse tags in XML files.

With that in mind, let’s take a look at how ServiceBean is read by Spring and injected into the Spring container. The various attempts to debug are not fully described here. To debug the dubbo code, see where the dubbo code refers to ServiceBean, and then break the relevant code (see package name, class name, interface implemented, parent class, method name). It would take too much space to describe the whole debugging process.

I’m using @importResource to get the Spring container to load the dubbo configuration file into the container.

package com.huang.dubboprovider.config;


import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource({"classpath:dubbo-provider.xml"})
public class ImportDubboProviderConfig {}Copy the code

The process by which the individual ServiceBean instances in dubo-provider.xml are created and injected into the Spring container is shown below. Only give a general process is good, clear key class name, later debug is also very convenient, not dizzy) :

Dubbo uses Spring’s SPI to specify the Dubbo XML file NamespaceHandler as the DubboNamespaceHandler:

DefaultNamespaceHandlerResolver, Handlers: Reads all meta-INF /spring.handlers files in the current Classloader, where the mapping between namespaceUri and the specific NamespaceHandler is recorded.

Therefore, DubboNamespaceHandler is automatically used when parsing dubbo-provider. XML.

DubboNamespaceHandler inherits from NamespaceHandlerSupport, which implements the NamespaceHandler interface. NamespaceHandler has only one init method, and DubboNamespaceHandler, in init, maps various types of tags in an XML file to their corresponding BeanDefinitionParser, Save to NamespaceHandlerSupport. Parsers (a HashMap).

Then through NamespaceHandlerSupport. Parsers to dubbo XML file total different types of labels to choose different types of DubboBeanDefinitionParser to resolve. Spring leaves the user with two “hooks” : the inti method of NamespaceHandler and the parsers field of NamespaceHandlerSupport. This “hook” method is essentially a template method pattern. The provider (superclass) creates the template, leaving the hook implementation to use the provider (subclass).

4. To summarize

Analyzing dubbo integration with Spring, exporting and registering services to the registry. As you can see, Spring provides at least three ways to extend or customize Spring behavior: the event mechanism (observer mode, publish/subscribe mode), the SPI mechanism, and the template method mode (hooks). There are many more Spring extension points, but all of them are the same. The core approach is still “interface programming,” subdividing functionality into interfaces that users can use to extend or change Spring’s behavior. A good understanding of the “interface oriented programming” approach will help us build programs that are easy to extend and maintain.

5. Source address

Dubbo and Springboot integration project source address (used to learn dubbo, debug) : github.com/ambition080…

6. Reference

Extending Spring Series (1)- Spring’s microkernel and FactoryBean extension mechanism

Dubbo official document – Service export

XML Schema-based configuration

XSD is introduced