Hola, I’m yes.

After two articles on RPC core and Dubbo microkernel, today we finally dive into a little bit of Dubbo.

As a generic RPC framework, performance is important, as is ease of use and extensibility.

A simple, non-invasive way to extend and customize RPC’s various phases of functionality has been a goal of many teams, and Dubbo fulfils these needs.

Through microkernel design and SPI extensions, it allows business teams with special needs to implement their own extensions in Dubbo without modifying the source code.

Dubbo’s success depends on this kind of design. Today we’ll take a look at how Dubbo achieves non-intrusive extensions, along with Dubbo’s IOC and AOP.

There is a precautionary first, today’s content code a little bit more, after all, want to in-depth analysis, source code is essential, just by the way also mentioned to see the source code tips.

Therefore, it is recommended to look on the computer, more clear and comfortable.

And if you haven’t seen the source code, follow the Dubbo series and you won’t be afraid to be asked if you’ve seen the source code.

SPI

Dubbo uses the Service Provider Interface (SPI) to implement the extension mechanism.

Java.sql.Driver is used to access a database.

There are a variety of databases on the market, and each database vendor has its own implementation, so we definitely need to customize an interface, so that we can program for the interface.

The implementation can be loaded through configuration, and that’s where the JDK SPI comes in.

It’s not magic at all, it’s just a convention where you go to find the implementation class when you load it.

The convention is that there is a dead directory in the code called meta-INF /services/.

Then create a file in that directory with the fully qualified name of the interface, and the contents of the file are the fully qualified name of the implementation class.

If you want to implement a class, look for it here based on the interface name and instantiate it.

This is the JDK SPI, but it doesn’t meet Dubbo’s requirements.

Because Dubbo has stripped out some of its own implementations as extensions, there are still a few of them, and you don’t need to use them all.

If you use the JDK SPI, you load all the classes in the configuration file, which leads to a waste of resources. When you use it, you have to go through the past to find the corresponding implementation.

So Dubbo implements a Dubbo SPI based on the JDK SPI, and can load implementation classes according to the specified name on demand. For example, in the case of Cluster, there are many implementation classes.

The agreed place has been changed, there are three directories.

  • Meta-inf /dubbo/internal/ : this is the SPI configuration file for internal use in Dubbo.
  • Meta-inf /dubbo/ : this is where the user – defined SPI configuration files are stored.
  • Meta-inf /services/ : compatible with JDK SPI

Then the contents of the file are in the form of key=value, so that you can find the corresponding implementation class according to the key.

You can then configure a default key on the annotations to select the default implementation class, such as Cluster, which implements failover by default.

The implementation class can also be selected using the URL parameter.

Also like JDK SPI extension point loading failure, even the extension point name can not get, when the time to report an error also do not know where the problem.

Dubbo SPI, on the other hand, is error-free and also provides auto-injection and AOP capabilities for extension points.

With a brief overview of Dubbo SPI, let’s dive into the implementation details.

Dubbo SPI implementation details

The core implementation of Dubbo SPI is in ExtensionLoader, which is responsible for extension point loading and lifecycle maintenance, similar to the ServiceLoader in JDK SPI.

Here to first mention a little look at the source of the small skills.

Open source frameworks will have unit tests, and unit tests will have the implementation of various functions we want when we look at the source code, we can start from the unit test to know some of the functional division, and then break debugging gradually in-depth.

For example, the ExtensionLoader in today’s article is in the Dubbo-common module. Let’s go to Test to see how it writes test cases.

Of course, in addition to the folder to find, directly with the file name search line.

It’s easy to find, the data is built, find the way you want to debug, a breakpoint set, arrow point, it’s not beautiful, isn’t it?

Ok, tips shared, back to ExtensionLoader, let’s take a quick look at the implementation using Dubbo unit test data.

There is a class called SimpleExt with three implementations, the default being IMPL1.

Looking at the contents of the SPI configuration file again, you can see that some Spaces have been deliberately written in the configuration file for testing purposes.

Now, if you want to find the impl2 implementation, you just call it.

SimpleExt ext = ExtensionLoader
    .getExtensionLoader(SimpleExt.class).getExtension("impl2") 
Copy the code

An extension interface pair should have an ExtensionLoader. Find the corresponding ExtensionLoader and load the implementation class with the corresponding name.

There will be source code, but it doesn’t matter, or very simple, want to go deep into the source code must pass.

The getExtensionLoader is static, and the logic is simple: find the ExtensionLoader corresponding to the interface from the cache, and return a new one if it cannot find one.

Now that we have ExtensionLoader, let’s take a look at the logic of getExtension and see how we can find the corresponding implementation class through the extension point name.

As you can see, there is a cache operation again, the logic is very simple, first go to the cache to find the instance, if not create the instance.

The best details are the use of double-check locks, and then holder to ensure visibility and prevent instruction reordering. ** The holder is a volatile and double-checked lock.

Let’s take a look at createExtension. This is to create the extension point. The code is a bit long, but I’ve commented it all out, including the green ones.

The logic is still very simple, the detailed code is not shown in detail, I will dictate it first.

  1. Use the interface class name to find the corresponding file in the three directories.
  2. The contents of the parsed file generate class objects, which are then cached in cachedClasses.
  3. Then use name to find the corresponding class object in cachedClasses.
  4. Cache EXTENSION_INSTANCES to see if it has been instantiated.
  5. If not, instantiate and then call injectExtension for automatic injection.
  6. The wrapper is implemented through cachedWrapperClasses, and the final wrapper class is returned.

It doesn’t matter if there are a few points that are not clear, let’s continue to analyze, have a general idea of what to do in mind first, and then see how to do it.

LoadDirectory in the source code is to go to the directory to find the file, and then parse, finally call loadClass, this method is very key, we analyze in detail, for easy viewing, delete some code.

Adaptive, we’re going to skip it, just know that it was recorded here.

Then the AOP related cachedWrapperClasses mentioned above are documented here, and what if it is a wrapper class?

Simple but effective, any class that has the current class as a constructor parameter is a wrapper class.

Now let’s go back to this code, Dubbo’s AOP.

Record the corresponding wrapper classes in cachedWrapperClasses, and then wrap the extension classes layer by layer when instantiating the extension class.

Why is this AOP? Because it cuts some logic into the extension implementation class.

The idea is to move the common logic of the extension object into the wrapper class, as we can see from the unit test example.

As you can see from the figure, there are two extension implementation classes and two wrapper classes. The specific logic is not important, but the configuration file is as follows:

When you look at the results of the unit test run, you can see that the Ext5Wrapper1 object is actually returned, and it also wraps the WRapper2 object.

So the echo method call chain is: Ext5Wrapper1 ->Ext5Wrapper2->Ext5impl1

It also has the effect of AOP.

Let’s look at injectExtension and see how it implements automatic injection of Dubbo.

Were you a little disappointed when you saw the code, that’s all?

Yes, it is that simple to determine whether there is a set method, and then find the object according to the parameters, perform set injection.

So there are no secrets under the source code, which seems like pretty advanced stuff, right there.

In the code above has a objectFactory. GetExtension (), this has something to do and the expansion of the adaptive, didn’t say there’s a @ Activate.

These contents are a little bit too much, also very important, feeling may be a little round, so write a separate article.

The last

Dubbo relies on SPI mechanism to extract communication protocol, serialization format, load balancing, routing policy and other parts as plug-ins to realize extension and customization.

The micro kernel and SPI mechanism meet the needs of user customization, and also ensure the stability and sustainability of the framework itself.

And Dubbo itself provides many existing implementations, such as various routing policies and so on.

So a good framework not only has to be fully functional, but it also has to be open to extension so that the ecosystem can grow.

Today’s code is still a bit much, if you do not understand the suggestion to download the source code, follow the source code debugging several times will be clear.

Source code this step must be in the past, in the past after easy.

Dubbo series continue to update, stay tuned, if you have any questions, please leave a comment, I will try to answer.

Wechat search “yes training level guide” full of dry goods, or to pinch me, reply [123] a 20W word algorithm brush notes waiting for you to get. More articles can see my article summary: github.com/yessimida/y… Welcome to star!


I am yes, from a little bit to a billion little bit, welcome to see, forward, leave a message, we will see you next.