Solomon_ Chaug shell architecture follows the Dubbo extensible mechanism for “bouncing” distributed microservices. Thumbs up, thumbs up, thumbs up.

Follow my public account Solomon for more surprises

Extension mechanism for Dubbo

On Dubbo’s website, Dubbo describes itself as a high-performance RPC framework. Today I want to talk about another great feature of Dubbo, which is its scalability. Just like Rome was not built in a day, any system must grow from a small system to a large system. It is impossible to design a system fully from the beginning. Instead, we should focus on the needs of the present and then iterate on the system. At the code level, we are required to properly abstract and isolate concerns so that the software remains well structured and maintainable as it continues to add functionality and features, while allowing third-party developers to extend its functionality. In some cases, software designers are more interested in scalability than performance.

When it comes to software design, scalability is often talked about. What exactly is scalability, and what kind of framework is good scalability? It has to do two things:

  • As the maintainer of the framework, when adding a new function, you only need to add some new code, instead of massively modifying the existing code, which conforms to the open closed principle.
  • As a framework user, when adding a new feature, you don’t need to modify the source code of the framework, you can add the code in your own project.

Dubbo does both well. This is thanks to Dubbo’s microkernel + plugin mechanism. In the following chapters we will uncover the mystery of Dubbo’s extension mechanism.

Several solutions are extensible

There are several common extendable implementations:

  • The Factory pattern
  • The IoC container
  • OSGI container

Dubbo, as a framework, does not want to rely heavily on other IoC containers such as Spring and Guice. OSGI is also a heavy implementation and not suitable for Dubbo. The final implementation of Dubbo references Java’s native SPI mechanism, but extends it to meet the needs of Dubbo.

Java mechanism of SPI

Since Dubbo’s extension mechanism is based on Java’s native SPI mechanism, let’s take a look at Java SPI first. Understand Java SPI, that is, to have a basic understanding of Dubbo’s extension mechanism. If you are familiar with the Java SPI, you can skip it.

Java SPI(Service Provider Interface) is an implementation of dynamically loading extension points built into JDK. In the META-INF/services directory of the ClassPath, place a text file with the same name as the interface. The file contains the implementation classes of the interface, separated by newlines. The JDK uses java.util.Serviceloader to load the concrete implementation. Let’s take a look at how the Java SPI works through a simple example.

Define an interface, IRepository, to implement data storage

public interface IRepository {
    void save(String data);
}
Copy the code

There are two implementations of IRepository. MysqlRepository and MongoRepository

public class MysqlRepository implements IRepository {
    public void save(String data) {
        System.out.println("Save " + data + " to Mysql"); }}Copy the code
public class MongoRepository implements IRepository {
    public void save(String data) {
        System.out.println("Save " + data + " to Mongo"); }}Copy the code

Add the configuration file In the meta-inf/services directory to add a file, the file name and interface full name is the same, so the file is meta-inf/services/com. Solomon. IRepository. The contents of the document are as follows:

com.solomon.MongoRepository com.solomon.MysqlRepository

Load the IRepository implementation with ServiceLoader

ServiceLoader<IRepository> serviceLoader = ServiceLoader.load(IRepository.class);
Iterator<IRepository> it = serviceLoader.iterator();
while(it ! =null && it.hasNext()){
    IRepository demoService = it.next();
    System.out.println("class:" + demoService.getClass().getName());
    demoService.save("tom");
}
Copy the code

In the example above, we defined an extension point and its two implementations. Add the extension configuration file to the ClassPath, and finally use the ServiceLoader to load all extension points. The final output results as follows: the class: testDubbo MongoRepository Save Tom to Mongo class: testDubbo. MysqlRepository Save Tom to Mysql

Dubbo’s SPI mechanism

The Java SPI is simple to use. The basic function of loading extension points is also done. But the Java SPI has the following disadvantages:

  • We need to go through all the implementations, instantiate them, and then we can find the implementation we need in the loop.
  • The configuration file simply lists all extension implementations without naming them. It is difficult to refer to them accurately in the program.
  • Extensions that depend on other extensions cannot be auto-injected and assembled
  • IOC and AOP capabilities similar to Spring are not provided
  • Extensions are difficult to integrate with other frameworks, such as relying on a Spring bean inside the extension, which is not supported by the native Java SPI

So the Java SPI can handle some simple scenarios, but for Dubbo, it’s still pretty weak. Dubbo extends the native SPI mechanism a bit. Next, let’s take a closer look at Dubbo’s SPI mechanism.

Basic concepts of Dubbo extension point mechanism

Before we dive into the extension mechanism of Dubbo, let’s clarify some basic concepts in Dubbo SPI. We’ll use these terms a lot in the rest of this article

Extension Point

  • Is a Java interface

Extension (Extension)

  • The implementation class of the extension point

Extension Instance

  • The extension point implements an instance of the class

Extension Adaptive Instance

This concept may not be easy to understand when you first encounter it (I did the same for the first time…). . It might be easier to understand if you call it an extended proxy class. An adaptive instance of an Extension is essentially a proxy for an Extension that implements the Extension point interface. When an extension point’s interface method is called, the actual parameters determine which extension to use. An extension point for IRepository, for example, has a save method. There are two implementations of MysqlRepository and MongoRepository. When an adaptive instance of IRepository calls an interface method, it decides which implementation of IRepository to call based on the parameters in the save method. If the method argument has repository=mysql, the MysqlRepository save method is called. If repository=mongo, MongoRepository’s save method is called. This is similar to object-oriented delayed binding. Why did Dubbo introduce the concept of extended adaptive instances?

  • There are two types of configuration in Dubbo. One is a fixed system-level configuration that does not change after Dubbo is started. There is also the run-time configuration, which may vary from RPC to RPC. For example, if the timeout is set to 10 seconds in the XML file, this configuration will not change after Dubbo is started. But for a particular RPC call, you can set its timeout to 30 seconds to override system-level configuration. For Dubbo, the parameters of each RPC call are unknown. Only at run time can correct decisions be made based on these parameters.
  • Most of the time, our class is a singleton, such as a Spring bean, when the Spring bean is instantiated, if it depends on an extension point, but when the bean is instantiated, it is not clear which specific extension should be used. This is where a proxy pattern is needed, which implements the extension point interface and dynamically selects the appropriate extension implementation within the method based on runtime parameters. And this proxy is an adaptive instance. Adaptive extension instances are used extensively in Dubbo. In Dubbo, each extension has an adaptive class, and if we don’t provide one, Dubbo automatically generates one for us using bytecode tools. So adaptive classes are almost invisible to us. Examples of how adaptive classes work will follow.

SPI

The @spi annotation applies to the interface of an extension point, indicating that the interface is an extension point. Can be loaded by Dubbo’s ExtentionLoader. The ExtensionLoader call is abnormal without this.

Adaptive

The @adaptive annotation is used for methods that extend interfaces. Indicates that the method is an adaptive method. When Dubbo generates an Adaptive instance for an extension point, it generates code for the method if it has the @adaptive annotation. The method’s internal parameters determine which extension to use. The @Adaptive annotation is used on the class to represent the implementation of a decorator class, similar to the decorator mode in design mode. Its main function is to return the specified class. At present, the AdaptiveCompiler and AdaptiveExtensionFactory classes have this annotation in the whole system.

ExtentionLoader

The Java SPI-like ServiceLoader is responsible for the loading and lifecycle maintenance of extensions

Extend the alias

Unlike the Java SPI, extensions in Dubbo have an alias for referencing them in your application. Such as

random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
Copy the code

Some of the path

Like Java SPI loading the extension configuration from the/meta-INF /services directory, Dubbo loads the extension configuration file from the following path:

  • META-INF/dubbo/internal
  • META-INF/dubbo
  • META-INF/services

Dubbo’s LoadBalance extension point interpretation

Now that you’ve looked at some of Dubbo’s basic concepts, let’s look at a practical extension point in Dubbo to get a more intuitive idea of these concepts.

We chose the LoadBalance extension point in Dubbo. A service in Dubbo usually has multiple providers. When invoking the service, a consumer needs to select one of these providers. This is a LoadBalance. Let’s take a look at how LoadBalance is an extension point in Dubbo.

LoadBalance interface

@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {

    @Adaptive("loadbalance")
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}
Copy the code

The LoadBalance interface has only one SELECT method. The select method selects one of multiple Invokers. The elements associated with Dubbo SPI in the code above are:

  • @spi (randomloadBalance-name) @spi applies to the LoadBalance interface, indicating that the interface LoadBalance is an extension point. If you try to load an extension without the @spi annotation, an exception will be thrown. The @spi annotation takes one parameter that represents the alias of the default implementation of the extension point. If no specified extension is displayed, the default implementation is used. Randomloadbalance-name is a constant with a value of “random”, which is an implementation of random load balancing. The definition of the random in the configuration file meta-inf/dubbo/internal/com. Alibaba. Dubbo. RPC. Cluster. LoadBalance:
random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
Copy the code

You can see that the file defines four extended implementations of LoadBalance. Since the implementation of load balancing is not the subject of this article, I will not elaborate on it here. Just know that Dubbo provides four load balancing implementations, one of which can be explicitly specified by XML files, properties files, and JVM parameters. If not, random is used by default

Get the LoadBalance extension

The code for getting LoadBalance in Dubbo is as follows:

LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName);
Copy the code

Use ExtensionLoader. GetExtensionLoader (LoadBalance. Class) method to obtain a ExtensionLoader instance, and then call getExtension, introduced into an extended an alias for the expansion of the corresponding instance.

conclusion

Starting with Java SPI, we have learned the basic concepts of Dubbo SPI and combined them with LoadBalance in Dubbo to deepen our understanding. Finally, we gave it a go, creating a custom LoadBalance and integrating it into Dubbo. I believe that through the combination of theory and practice here, you will have a deeper understanding of the scalability of Dubbo. To sum up, Dubbo SPI has the following characteristics:

  • Extensions to Dubbo do not require any changes to Dubbo’s source code
  • The custom extension point implementation of Dubbo, which is a plain Java class, does not introduce any Dubbo-specific elements and is virtually non-intrusive to the code.
  • To register the extension with Dubbo, simply add the configuration file to your ClassPath. Simple to use. And it doesn’t affect existing code. In line with the open and close principle.
  • Dubbo extension mechanism design Default: @spi (” dubbo “) represents the default SPI object
  • Dubbo’s extension mechanism supports IoC,AoP and other advanced features
  • Dubbo’s extension mechanism works well with third-party IoC containers. Spring beans are supported by default and can be extended to support other containers, such as Google’s Guice.
  • To switch the implementation of an extension point, you only need to change the implementation in the configuration file, without changing the code. Easy to use.

yourLike and followIs the continuing power of the Solomon_ Shogo shell structure.

Hot historical Articles

  • 🔥Serverless Microservices elegant shutdown practices

  • 🔥 this algorithm can not understand! How are the 9 images presented

  • 🔥SpringBoot Mastery – Custom Condition annotations (Series 1)

  • 🔥Java is how to take off the beautiful woman’s clothes

  • 🔥 High-performance gateway was originally designed this way

  • 🔥REST FUL look still don’t understand, you play me!

  • How much 🔥Serverless affects programmers

  • 🔥 How does distributed transaction XID connect all microservices in tandem

  • 🔥 Microservices Distributed Transaction TCC core implementation

  • 🔥 hundreds of millions of traffic site performance optimization methodology steps

  • 🔥 microservice Nacos implements proximity access through CMDB to improve performance

  • 🔥 Micro service architecture DNS service registration and discovery mechanism

  • . More and more

Chat 🏆 technology project stage v | distributed those things…