SPI for Dubbo Source Analysis

1. Overview

This is the second article on source analysis of dubbo SPI, followed by the first to continue with analysis of dubbo SPI, focusing on the getDefaultExtension() method for obtaining default extension points.

Because this method is simple, we skip the example section and analyze the source code directly.

2. Source Code Analysis

Getting the default extension method getDefaultExtension() is a public, externally accessible method.We know that extension point interfaces in dubbo must be decorated with @SPI annotations, and the @SPI annotation code is as follows:

 1 @Documented
 2 @Retention(RetentionPolicy.RUNTIME)
 3 @Target({ElementType.TYPE})
 4 public @interface SPI {
 6     /**
 7      * default extension name
 8      */
 9     String value() default "";
11 }

Annotations can decorate classes and interfaces while providing a value field that is empty by default.

This value field is the default extension implementation described in this article.

Now let's look inside the getDefaultExtension() method:

1 public T getDefaultExtension() {
2     getExtensionClasses();
3     // cachedDefaultName by@SPI In value
4     if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) {
5         return null;
6     }
7     return getExtension(cachedDefaultName);
8 }

The second line of method, getExtensionClasses(), loads a configuration text file to get the configured extension point implementation class. When the method is executed, the key of the configuration text file and the Class object of the extension point implementation class are stored in the cachedClasses member variable, as we described in the first article.

The next key point of the method is that the member variable cachedDefaultName determines that if cachedDefaultName is empty or "true" returns null directly, or if cachedDefaultName is not empty, the getExtension(.) method is called to return the extension point implementation class object.This method was also described in the first article.Now all we need to do is analyze the assignment points for cachedDefaultName.

The member variable cachedDefaultName was introduced in the first article and we don't know if you're still impressed. Now let's look at the variable definition:

1 // SPI()within value,Default interface implementation
2 private String cachedDefaultName;

Private string variable.

The assignment of variable cachedDefaultName is actually done during the loading of the configuration text file. The specific method call chain is:

1 getDefaultExtension() -->getExtensionClasses()-->loadExtensionClasses()

Now that we've covered all of these methods, let's look at the loadExtensionClasses():

 1 private Map<String, Class<?>> loadExtensionClasses() {
 2     // Get annotations SPI Interface
 3     // type For the incoming extension interface, you must have@SPI annotation
 4     final SPI defaultAnnotation = type.getAnnotation(SPI.class);
 5     // Get the default extension implementation value,If present, assign to cachedDefaultName
 6     if (defaultAnnotation != null) {
 7         String value = defaultAnnotation.value();
 8         if ((value = value.trim()).length() > 0) {
 9             // @SPI value Can only be one, not multiple for commas
10             // @SPI value Implement for default extensions
11             String[] names = NAME_SEPARATOR.split(value);
12             if (names.length > 1) {
13                 throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names));
14             }
15             if (names.length == 1)
16                 cachedDefaultName = names[0];
17         }
18     }
19     // Load extension classes for three directory configurations
20     Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
21     // META-INF/dubbo/internal
22     loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
23     // META-INF/dubbo
24     loadDirectory(extensionClasses, DUBBO_DIRECTORY);
25     // META-INF/services/
26     loadDirectory(extensionClasses, SERVICES_DIRECTORY);
27     return extensionClasses;
28 }

Yes, this is the only assignment to cachedDefaultName.

The content of cachedDefaultName is the value content that parses the @SPI comment.After assigning a value here, the return of the getDefaultExtension() method is obtained and returned from the extension point based on this value.

3. Summary

The logic of the getDefaultExtension() method to get the default extension point is simple: it parses the value content of the comment @SPI and gets the extension point using the getExtension(.) method described in the previous article.The getDefaultExtension() method returns null if @SPI is not configured with value or set to true.

Keywords: Java Dubbo

Added by bluethundr on Tue, 17 Dec 2019 05:42:18 +0200