甜腻的嘴角|Dubbo如何通过SPI提高框架的可扩展性?( 三 )

我跑这个代码的时候直接报异常 , 看了一下官网才发现dubbo是可以注入接口的实现的 , 但不像spring那么智能 , dubbo必须用URL(类似总线)来指定扩展类对应的实现类. 。 这就不得不提到@Adaptive注解了
自适应使用@Adaptive注解 , 动态的通过URL中的参数来确定要使用哪个具体的实现类
@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})public @interface Adaptive {String[] value() default {};}@SPIpublic interface Wheel {@Adaptive("wheel")void getBrandByUrl(URL url);}public class BenzWheel implements Wheel {@Overridepublic void getBrandByUrl(URL url) {System.out.println("benzWheel");}}@SPIpublic interface Car {void getBrandByUrl(URL url);}public class BenzCar implements Car {// 这个里面存的是代理对象private Wheel wheel;public void setWheel(Wheel wheel) {this.wheel = wheel;}@Overridepublic void getBrandByUrl(URL url) {System.out.println("benzCar");// 代理类根据URL找到实现类 , 然后再调用实现类wheel.getBrandByUrl(url);}}public class DubboSpiIocDemo {public static void main(String[] args) {ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);Car car = extensionLoader.getExtension("benz");Map map = new HashMap<>();// 指定wheel的实现类为benzmap.put("wheel", "benz");URL url = new URL("", "", 1, map);// benzCar// benzWheelcar.getBrandByUrl(url);}}可以看到BenzCar对象成功注入了BenzWheel 。BenzCar中其实注入的是BenzWheel的代码对象 , 这个代理对象会根据@Adaptive("wheel")获取到wheel , 然后从url中找到key为wheel的值 , 这个值即为实现类对应的key 。
上面的注释提到BenzCar里面注入的Wheel其实是一个代理对象(框架帮我们生成) , 在代理对象中根据url找到相应的实现类 , 然后调用实现类 。
因为代理对象是框架在运行过程中帮我们生成的 , 没有文件可以查看 , 所以用Arthas来查看一下生成的代理类
curl -O java -jar arthas-boot.jar# 根据前面的序号选择进入的进程 , 然后执行下面的命令jad org.apache.dubbo.adaptive.Wheel$Adaptive生成的Wheel
package org.apache.dubbo.adaptive;import org.apache.dubbo.adaptive.Wheel;import org.apache.dubbo.common.URL;import org.apache.dubbo.common.extension.ExtensionLoader;public class Wheel$Adaptiveimplements Wheel {public void getBrandByUrl(URL uRL) {if (uRL == null) {throw new IllegalArgumentException("url == null");}URL uRL2 = uRL;String string = uRL2.getParameter("wheel");if (string == null) {throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.adaptive.Wheel) name from url (").append(uRL2.toString()).append(") use keys([wheel])").toString());}Wheel wheel = (Wheel)ExtensionLoader.getExtensionLoader(Wheel.class).getExtension(string);wheel.getBrandByUrl(uRL);}}@Adaptive可以标记在类上或者方法上
标记在类上:将该实现类直接作为默认实现 , 不再自动生成代码标记在方法上:通过参数动态获得实现类 , 比如上面的例子
用源码演示一下用在类上的@Adaptiv , Dubbo为自适应扩展点生成代码 , 如我们上面的WheelAdaptive类如下所示¨G30G??@Adaptive可以标记在类上或者方法上??标记在类上:将该实现类直接作为默认实现 , 不再自动生成代码标记在方法上:通过参数动态获得实现类 , 比如上面的例子用源码演示一下用在类上的@Adaptiv , Dubbo为自适应扩展点生成代码 , 如我们上面的WheelAdaptive , 但生成的代码还需要编译才能生成class文件 。 我们可以用JavassistCompiler(默认的)或者JdkCompiler来编译(需要配置) , 这个小小的功能就用到了@Adaptive


推荐阅读