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

Introduction of SPI Mechanism of Dubbo and Adaptive example

2025-01-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

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

This article mainly explains "the introduction of SPI mechanism of Dubbo and the example of Adaptive". The content of the explanation in this article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "the introduction of SPI mechanism of Dubbo and Adaptive example".

1. @ Adaptive example of Dubbo @ SPI ("dubbo") public interface AdaptiveExt {@ Adaptive / / Unit Test method 4 is annotated as @ Adaptive ({"t"}) String echo (String msg, URL url);} public class DubboAdaptiveExt implements AdaptiveExt {@ Override public String echo (String msg, URL url) {return "dubbo";}} public class SpringCloudAdaptiveExt implements AdaptiveExt {@ Override public String echo (String msg, URL url) {return "spring cloud" }} / / add @ Adaptive annotation to unit test 3, and the rest do not add @ Adaptivepublic class ThriftAdaptiveExt implements AdaptiveExt {@ Override public String echo (String msg, URL url) {return "thrift";}}

At the same time, you should create a new META-INF/dubbo folder and a new com.alibaba.dubbo.demo.provider.adaptive.AdaptiveExt under the resources directory, that is, the fully qualified name file of the API, with the following contents:

Dubbo=com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExtcloud=com.alibaba.dubbo.demo.provider.adaptive.impl.SpringCloudAdaptiveExtthrift=com.alibaba.dubbo.demo.provider.adaptive.impl.ThriftAdaptiveExt

Here are four unit test cases. Looking at the output of the four test cases, we can draw the following conclusions:

From test 3, we can see that if the implementation class is annotated with @ Adaptive, it has the highest priority, and getAdaptiveExtension () creates an instance of this class.

From test 1, if there is a value on the SP annotation, and there is no value in the url parameter, and there is no class annotation @ Adaptive annotation, then create an instance of the class corresponding to the key of dubbo.

From test 4, we can see that if there is an annotation @ Adpative ({"t"}) on the method, the parameter t=cloud should be added to the URL to create an instance corresponding to cloud.

From test 2, we can see that the method has the annotation @ Adaptive, and URL is configured with the default parameter, which is generated by AdaptiveExt through lowercase conversion (adaptive.ext=cloud), then an instance of the corresponding class of cloud is created. As you can see, test 2 is similar to test 4. As long as there are parameters in URL and the configuration is correct, the value on the @ SPI annotation is ignored.

So you can get priority: @ Adaptive annotated class > URL parameter > @ SPI annotation value

/ * there is a note on SPI, @ SPI ("dubbo"), url has no parameter, no @ Adaptive note is added on the class, and no parameter is added on the method @ Adaptive note. Output dubbo * / @ Testpublic void test1 () {ExtensionLoader loader = ExtensionLoader.getExtensionLoader (AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getAdaptiveExtension (); URL url = URL.valueOf ("test://localhost/test"); System.out.println (adaptiveExtension.echo ("d", url)) } / * SPI has a note, @ SPI ("dubbo"), URL also has a specific value, output spring cloud, note that the method is marked with @ Adaptive note here, but the note has no value * / @ Testpublic void test2 () {ExtensionLoader loader = ExtensionLoader.getExtensionLoader (AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getAdaptiveExtension (); URL url = URL.valueOf ("test://localhost/test?adaptive.ext=cloud") System.out.println (adaptiveExtension.echo ("d", url));} / * SPI is annotated, @ SPI ("dubbo"), URL also has a specific value, ThriftAdaptiveExt implementation class has @ Adaptive annotation above, output thrift * / @ Testpublic void test3 () {ExtensionLoader loader = ExtensionLoader.getExtensionLoader (AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getAdaptiveExtension (); URL url = URL.valueOf ("test://localhost/test?adaptive.ext=cloud") There are annotations on System.out.println (adaptiveExtension.echo ("d", url));} / * * SPI, @ SPI ("dubbo"), and specific values in URL. Note @ Adaptive ({"t"}) is added to the API method, and there is no * @ Adaptive annotation on each implementation class. Output spring cloud * / @ Testpublic void test4 () {ExtensionLoader loader = ExtensionLoader.getExtensionLoader (AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getAdaptiveExtension () URL url = URL.valueOf ("test://localhost/test?t=cloud"); System.out.println (adaptiveExtension.echo ("d", url));} 2. Dubbo's @ Adaptive adaptive extension mechanism source code analysis 2.1, test case 1

First of all, the source code corresponding to the test case is analyzed first, and the other cases are all the same. after a thorough analysis, the rest are naturally clear.

There are comments on / / SPI, @ SPI ("dubbo"), url has no parameters, no @ Adaptive notes have been added on the class, and @ Adaptive notes have no parameters on the method @ Adaptive. Output dubbo@Testpublic void test1 () {ExtensionLoader loader = ExtensionLoader.getExtensionLoader (AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getAdaptiveExtension (); URL url = URL.valueOf ("test://localhost/test"); System.out.println (adaptiveExtension.echo ("d", url)) } public T getAdaptiveExtension () {Object instance = cachedAdaptiveInstance.get (); if (instance = = null) {if (createAdaptiveInstanceError = = null) {synchronized (cachedAdaptiveInstance) {instance = cachedAdaptiveInstance.get () If (instance = = null) {try {/ / create an adaptive extension proxy class object and put it in the cache instance = createAdaptiveExtension (); cachedAdaptiveInstance.set (instance) } catch (Throwable t) {/ / throw exception} else {/ / throw exception}} return (T) instance } private T createAdaptiveExtension () {try {/ / is divided into three steps: 1 is to create an adaptive extension proxy class Class object, 2 is to create an object through reflection, and 3 is to inject return injectExtension ((T) getAdaptiveExtensionClass () .newInstance ()) into the created object on-demand dependency } catch (Exception e) {/ / throw exception}} private Class getAdaptiveExtensionClass () {/ / load the implementation class getExtensionClasses () marked with @ SPI annotation from the default directory; / / if the @ Adaptive annotation implementation class is marked, then cachedAdaptiveClass is not empty, just return if (cachedAdaptiveClass! = null) {return cachedAdaptiveClass } / / create an adaptive extension agent class class file return cachedAdaptiveClass = createAdaptiveExtensionClass ();} private Class createAdaptiveExtensionClass () {/ / code saves the created class string data String code = createAdaptiveExtensionClassCode (); ClassLoader classLoader = findClassLoader (); Compiler compiler = ExtensionLoader.getExtensionLoader (Compiler.class). GetAdaptiveExtension (); return compiler.compile (code, classLoader) } private String createAdaptiveExtensionClassCode () {/ / is used to store the generated proxy class class file StringBuilder codeBuilder = new StringBuilder (); / / traverses all the methods of the interface marked with @ SPI annotation, which is analyzed here as com.alibaba.dubbo.demo.provider.adaptive.AdaptiveExt Method [] methods = type.getMethods () / / at least one of these methods should be annotated by @ Adaptive, otherwise there is no need to generate an adaptive proxy class and simply throw an exception boolean hasAdaptiveAnnotation = false; for (Method m: methods) {if (m.isAnnotationPresent (Adaptive.class)) {hasAdaptiveAnnotation = true; break;}} / / no need to generate adaptive class since there's no adaptive method found. If (! hasAdaptiveAnnotation) / / throw exception / / generate package information, such as package com.alibaba.dubbo.demo.provider.adaptive; codeBuilder.append ("package") .append (type.getPackage (). GetName ()) .append (";"); / / generate guided package information, such as import com.alibaba.dubbo.common.extension.ExtensionLoader; codeBuilder.append ("\ nimport") .append (ExtensionLoader.class.getName ()) .append (";") / / generate a class name like public class AdaptiveExt$Adaptive / / implements com.alibaba.dubbo.demo.provider.adaptive.AdaptiveExt {codeBuilder.append ("\ npublic class") .append (type.getSimpleName ()) .append ("$Adaptive"). Append ("implements") .append (type.getCanonicalName ()) .append ("{"); / / traverses all methods, generating proxy methods for (Method method: methods) {/ / method returns values, parameters, and throws exceptions Class rt = method.getReturnType (); Class [] pts = method.getParameterTypes (); Class [] ets = method.getExceptionTypes () / / get the Adaptive comment on the method. If there is no such comment on the method, throw an exception Adaptive adaptiveAnnotation = method.getAnnotation (Adaptive.class) for the method directly; StringBuilder code = new StringBuilder If (adaptiveAnnotation = = null) {code.append ("throw new UnsupportedOperationException (\" method ") .append (method.toString ()) .append (" of interface ") .append (type.getName ()) .append (" is not adaptive method!\ ");") } else {/ / urlTypeIndex is used to record the parameter URL in the parameter position, where String echo (String msg, URL url); / / in position 1, int urlTypeIndex =-1; for (int I = 0; I

< pts.length; ++i) { if (pts[i].equals(URL.class)) { urlTypeIndex = i; break; } } // 找到了URL参数 if (urlTypeIndex != -1) { // 空指针检查 // s形如:if (arg1 == null) throw new IllegalArgumentException("url == null"); String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",urlTypeIndex); code.append(s); // s形如:com.alibaba.dubbo.common.URL url = arg1; s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex); code.append(s); } // 没找到,暂不分析,TODO // 获取方法上的Adaptive注解的值,@Adaptive({"t"}),这里是t String[] value = adaptiveAnnotation.value(); // 如果@Adaptive注解没有值,对应第二种测试情况,从接口名生成从url中获取参数的key, // key为adaptive.ext,获取参数为url.getParameter("adaptive.ext", "dubbo") // 因为第二种情况URL中传递了adaptive.ext这个参数, // 所以String extName = url.getParameter("t", "dubbo");中获取的是cloud if (value.length == 0) { char[] charArray = type.getSimpleName().toCharArray(); StringBuilder sb = new StringBuilder(128); for (int i = 0; i < charArray.length; i++) { if (Character.isUpperCase(charArray[i])) { if (i != 0) { sb.append("."); } sb.append(Character.toLowerCase(charArray[i])); } else { sb.append(charArray[i]); } } value = new String[]{sb.toString()}; } // hasInvocation 暂不分析,TODO // defaultExtName是dubbo,cachedDefaultName = names[0],这个值是@SPI("dubbo")里的 String defaultExtName = cachedDefaultName; String getNameCode = null; for (int i = value.length - 1; i >

= 0 -- I) {if (I = = value.length-1) {if (null! = defaultExtName) {if (! "protocol" .equals (value [I]) if (hasInvocation) getNameCode = String.format ("url.getMethodParameter (methodName) \ "% s\",\ "% s\"), value [I], defaultExtName) Else / / such as: url.getParameter ("t", "dubbo") / / understanding is to see if the t parameter is passed in url. If it is passed, it will prevail in url. Otherwise, the default value getNameCode = String.format in / / @ SPI ("dubbo") will be taken as "url.getParameter (\"% s\ ",\"% s\ ")". " Value [I], defaultExtName) Else getNameCode = String.format ("(url.getProtocol () = = null?\"% s\ ": url.getProtocol ())", defaultExtName) } else {if (! "protocol" .equals (value [I]) if (hasInvocation) getNameCode = String.format ("url.getMethodParameter (methodName) \ "% s\",\ "% s\"), value [I], defaultExtName) Else getNameCode = String.format ("url.getParameter (\"% s\ ")", value [I]); else getNameCode = "url.getProtocol ()" }} else {if (! "protocol" .equals (value [I]) if (hasInvocation) getNameCode = String.format ("url.getMethodParameter (methodName,\"% s\ ") \ "% s\"), value [I], defaultExtName) Else getNameCode = String.format ("url.getParameter (\"% s\ ",% s)", value [I], getNameCode) Else getNameCode = String.format ("url.getProtocol () = = null? (% s): url.getProtocol ()", getNameCode);}} / / such as: String extName = url.getParameter ("t", "dubbo") / / this extName is which proxy class code.append ("\ nString extName =") .append (getNameCode) .append (";") is generated for the interface marked by @ SPI; / / check extName = = null? / / such as: if (extName = = null) throw new IllegalStateException ("...") String s = String.format ("\ nif (extName = = null)" + "throw new IllegalStateException (\" Fail to get extension (% s) name from url (\ "+ url.toString () +\") use keys (% s)\ ") ", type.getName (), Arrays.toString (value); code.append (s); / / AdaptiveExt extension = (AdaptiveExt) / / ExtensionLoader.getExtensionLoader (AdaptiveExt.class) .getExtension (extName); s = String.format ("\ n% s extension = (%) ")

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

Internet Technology

Wechat

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

12
Report