Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the SPI adaptation of Dubbo

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "how to understand Dubbo's SPI adaptation". In daily operation, I believe many people have doubts about how to understand Dubbo's SPI adaptation. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts of "how to understand Dubbo's SPI adaptation"! Next, please follow the editor to study!

First define a SPI interface (marked by @ SPI):

Import org.apache.dubbo.common.URL;import org.apache.dubbo.common.extension.Adaptive;import org.apache.dubbo.common.extension.SPI;@SPIpublic interface SpiIf {@ Adaptive void test1 (URL url); @ Adaptive void test2 (ObjHasUrl ohu); void test3 (URL url); void test4 (String name);}

The ObjHasUrl here is an object with an internal URL attribute, and the reason why it should have a URL attribute will be discussed below.

Next, define two implementation classes, Spi1 and Spi2:

Public class Spi1 implements SpiIf {@ Override public void test1 (URL url) {System.out.println ("This is Spi1:test1");} @ Override public void test2 (ObjHasUrl ohu) {System.out.println ("This is Spi1:test2");} @ Override public void test3 (URL url) {System.out.println ("This is Spi1:test3") } @ Override public void test4 (String name) {System.out.println ("This is Spi1:test4");}} public class Spi2 implements SpiIf {@ Override public void test1 (URL url) {System.out.println ("This is Spi2:test1");} @ Override public void test2 (ObjHasUrl ohu) {System.out.println ("This is Spi2:test2") } @ Override public void test3 (URL url) {System.out.println ("This is Spi2:test3");} @ Override public void test4 (String name) {System.out.println ("This is Spi2:test4");}}

The final step is to define a Runner test initiator:

Public class Runner {public static void main (String [] args) {URL url = new URL ("dubbo", "123,999"); url = url.addParameter ("spi.if", "S2"); / / set the url value to get the adaptive extension S2 of SpiTest. SpiIf spiIf = ExtensionLoader.getExtensionLoader (SpiIf.class). GetAdaptiveExtension (); spiIf.test1 (url); ObjHasUrl ohu = new ObjHasUrl (url); spiIf.test2 (ohu); url = url.addParameter ("spi.if", "S1"); SpiIf spiIf2 = ExtensionLoader.getExtensionLoader (SpiIf.class). GetAdaptiveExtension (); spiIf.test2 (ohu);}}

The above classes can be copied directly to your local project DEBUG.

When we start Runner, the first step is to look at the getExtensionLoader method. Here we start to enter the code of Dubbo:

Public static ExtensionLoader getExtensionLoader (Class type) {if (type = = null) {throw new IllegalArgumentException ("Extension type = = null");} / / verify whether it is the interface if (! type.isInterface ()) {throw new IllegalArgumentException ("Extension type (" + type + ") is not an interface!") } / / verify whether there are SPI annotations if (! withExtensionAnnotation (type)) {throw new IllegalArgumentException ("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName () + "!");} ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get (type) If (loader = = null) {EXTENSION_LOADERS.putIfAbsent (type, new ExtensionLoader (type)); loader = (ExtensionLoader) EXTENSION_LOADERS.get (type);} return loader;}

This step is mainly to get the ExtensionLoader object, mainly to do some verification of the interface class, to confirm that it is an extension point (with SPI comments).

The second step is to enter ExtensionLoader's getAdaptiveExtension method:

Public T getAdaptiveExtension () {/ / find cache Object instance = cachedAdaptiveInstance.get (); if (instance = = null) {if (createAdaptiveInstanceError! = null) {throw new IllegalStateException ("Failed to create adaptive instance:" + createAdaptiveInstanceError.toString (), createAdaptiveInstanceError) } / / if there is no cache, start creating synchronized (cachedAdaptiveInstance) {instance = cachedAdaptiveInstance.get (); if (instance = = null) {try {instance = createAdaptiveExtension (); cachedAdaptiveInstance.set (instance) } catch (Throwable t) {createAdaptiveInstanceError = t; throw new IllegalStateException ("Failed to create adaptive instance:" + t.toString (), t);} return (T) instance;}

The main purpose of this step is to get the actual list of the implementation objects of the interface and continue to analyze the method of actually creating the extension point:

Private T createAdaptiveExtension () {try {return injectExtension ((T) getAdaptiveExtensionClass (). NewInstance ());} catch (Exception e) {throw new IllegalStateException ("Can't create adaptive extension" + type + ", cause:" + e.getMessage (), e);}}

This step is divided into two steps, the first step: getAdaptiveExtensionClass, the second step: injectExtension

Step one:

Private Class getAdaptiveExtensionClass () {getExtensionClasses (); if (cachedAdaptiveClass! = null) {return cachedAdaptiveClass;} return cachedAdaptiveClass = createAdaptiveExtensionClass ();} private Class createAdaptiveExtensionClass () {String code = new AdaptiveClassCodeGenerator (type, cachedDefaultName). Generate (); ClassLoader classLoader = findClassLoader () Org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader (org.apache.dubbo.common.compiler.Compiler.class). GetAdaptiveExtension (); return compiler.compile (code, classLoader);}

The point is that when you create a class, you generate a code (actually SpiIf$Adaptive- > SpiIf, an implementation class):

Import org.apache.dubbo.common.extension.ExtensionLoader;public class SpiIf$Adaptive implements SpiIf {public void test2 (com.zf.server.authserver.spi.dubbospitest2.ObjHasUrl arg0) {if (arg0 = = null) throw new IllegalArgumentException ("com.zf.server.authserver.spi.dubbospitest2.ObjHasUrl argument = = null"); if (arg0.getUrl () = = null) throw new IllegalArgumentException ("com.zf.server.authserver.spi.dubbospitest2.ObjHasUrl argument getUrl () = = null") Org.apache.dubbo.common.URL url = arg0.getUrl (); String extName = url.getParameter ("spi.if"); if (extName = = null) throw new IllegalStateException ("Failed to get extension (com.zf.server.authserver.spi.dubbospitest2.SpiIf) name from url (" + url.toString () + ") use keys ([spi.if])") Com.zf.server.authserver.spi.dubbospitest2.SpiIf extension = (com.zf.server.authserver.spi.dubbospitest2.SpiIf) ExtensionLoader.getExtensionLoader (com.zf.server.authserver.spi.dubbospitest2.SpiIf.class) .getExtension (extName); extension.test2 (arg0);} public void test1 (org.apache.dubbo.common.URL arg0) {if (arg0 = = null) throw new IllegalArgumentException ("url = = null"); org.apache.dubbo.common.URL url = arg0 String extName = url.getParameter ("spi.if"); if (extName = = null) throw new IllegalStateException ("Failed to get extension (com.zf.server.authserver.spi.dubbospitest2.SpiIf) name from url (" + url.toString () + ") use keys ([spi.if])") Com.zf.server.authserver.spi.dubbospitest2.SpiIf extension = (com.zf.server.authserver.spi.dubbospitest2.SpiIf) ExtensionLoader.getExtensionLoader (com.zf.server.authserver.spi.dubbospitest2.SpiIf.class) .getExtension (extName); extension.test1 (arg0) } public void test3 (org.apache.dubbo.common.URL arg0) {throw new UnsupportedOperationException ("The method public abstract void com.zf.server.authserver.spi.dubbospitest2.SpiIf.test3 (org.apache.dubbo.common.URL) of interface com.zf.server.authserver.spi.dubbospitest2.SpiIf is not adaptive method!") } public void test4 (java.lang.String arg0) {throw new UnsupportedOperationException ("The method public abstract void com.zf.server.authserver.spi.dubbospitest2.SpiIf.test4 (java.lang.String) of interface com.zf.server.authserver.spi.dubbospitest2.SpiIf is not adaptive method!");}}

If you take a closer look, you can see that you have actually generated an implementation class for our interface. Then the actual content is generated for the Adaptive annotation method (that is, the actual extension class is obtained based on the URL parameter), which also explains the actual role of the Adaptive annotation.

One more thing to note: test1 provides parameters for URL, and test2 provides objects that contain URL attributes. What they all have in common is that they all contain a URL, and if they are not provided, they will indicate that there are no URL exceptions. You can analyze the specific reasons by yourself as follows:

New AdaptiveClassCodeGenerator (type, cachedDefaultName). Generate ()

Finally, the generated implementation class is loaded.

Step 2: injectExtension

Private T injectExtension (T instance) {if (objectFactory = = null) {return instance;} try {for (Method method: instance.getClass (). GetMethods ()) {if (! isSetter (method)) {continue } if (method.getAnnotation (DisableInject.class)! = null) {continue;} Class pt = method.getParameterTypes () [0]; if (ReflectUtils.isPrimitives (pt)) {continue } try {String property = getSetterProperty (method); Object object = objectFactory.getExtension (pt, property); if (object! = null) {method.invoke (instance, object) }} catch (Exception e) {logger.error ("Failed to inject via method" + method.getName () + "of interface" + type.getName () + ":" + e.getMessage (), e) } catch (Exception e) {logger.error (e.getMessage (), e);} return instance;}

And what does this step do? To put it simply, the circular set method, if the parameter type is also an adaptive extension point, continue the above steps to get the extension point object and reflect the injection, which implements the Dubbo version of dependency injection.

At this point, the instance of the resulting object-> SpiIf$Adaptive is returned and cached in cachedAdaptiveInstance, and the corresponding extension class is obtained according to the parameter value of url in Runner.

Summary:

1. The adaptive extension interface needs SPI annotation, the method needs Adaptive annotation, and the Adaptive method needs URL parameter or object parameter with URL attribute.

2. Finally, the API implementation class object SpiIf$Adaptive is returned, which encapsulates the method of obtaining the extended object according to the url parameter.

At this point, the study on "how to understand Dubbo's SPI adaptation" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report