- 该类要实现 SPI 接口
- 该类中要有 SPI 接口的引用
- 该类中必须含有一个含参的构造方法且参数只能有一个类型为SPI借口
- 在接口实现方法中要调用 SPI 接口引用对象的相应方法
- 该类名称以 Wrapper 结尾
@SPI("ali") // 默认的值支付宝支付 public interface Pay { // 接口的方法需要添加这个注解,在测试代码中,参数至少要有一个URL类型的参数 @Adaptive({"paytype"}) // 付款方式 void pay(URL url); } public class AliPay implements Pay { @Override public void pay(URL url) { System.out.println("使用支付宝支付"); } } public class WechatPay implements Pay { @Override public void pay(URL url) { System.out.println("使用微信支付"); } } 在/dubbo-common/src/main/resources/META-INF/services/com.test.Pay文件下添加内容如下: wechat = com.test.WechatPay ali = com.test.AliPay
public static void main(String[] args) { ExtensionLoader<Pay> loader = ExtensionLoader.getExtensionLoader(Pay.class); Pay pay = loader.getAdaptiveExtension(); pay.pay(URL.valueOf("http://localhost:9999/xxx")); // 使用支付宝支付 pay.pay(URL.valueOf("http://localhost:9999/xxx?paytype=wechat")); // 使用微信支付 }
- 首先要添加一个Wrapper类
- 并在/dubbo-common/src/main/resources/META-INF/services/com.test.Pay文件下追加“xxx = com.test.PayWrapper1”
public class PayWrapper1 implements Pay { Pay pay; public PayWrapper1(Pay pay) { this.pay = pay; } @Override public void pay(URL url) { System.out.println("pay before..."); pay.pay(url); System.out.println("pay after..."); } }
pay before...
使用支付宝支付
pay after...
pay before...
使用微信支付
pay after...
由此可见Wrapper是一个AOP功能
public class PayWrapper2 implements Pay { Pay pay; public PayWrapper2(Pay pay) { this.pay = pay; } @Override public void pay(URL url) { System.out.println("-----pay before..."); pay.pay(url); System.out.println("-----pay after..."); } }
并追加xxx2 = com.test.PayWrapper2
-----pay before...
pay before...
使用支付宝支付
pay after...
-----pay after...
执行顺序先执行2,再执行1
public static void main(String[] args) { URL url = URL.valueOf("http://localhost:9999/xxx"); String extName = url.getParameter("paytype", "ali"); System.out.println(extName); // ali ExtensionLoader<Pay> loader = ExtensionLoader.getExtensionLoader(Pay.class); Pay extension = (Pay) loader.getExtension(extName); // extension返回的结果为PayWrapper1 extension.pay(url); }
Wrapper功能实现分为两个部分
// 维护一个线程安全的HashSet来存放Wrapper try { // 尝试取得参数类型为SPI接口类型的构造函数,即判断该类是否是Wrapper类,如果不是会抛出异常;如果是,继续执行,并添加到cache中 // 上面定义的Wrapper类如果有构造,则表示是一个真正的Wrapper clazz.getConstructor(type); Set<Class<?>> wrappers = cachedWrapperClasses; // 通过上面取得ExtensionLoader的代码你需要知道,每一个SPI接口都有一个ExtensionLoader, // 所以这里面的缓存也是每一个SPI接口都有他的Wrapper缓存,生命周期和loader的生命周期一致 if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } // 这里cachedWrapperClasses和wrappers用的是同一个对象地址,所以相当于往cachedWrapperClasses添加元素 wrappers.add(clazz); }
private T createExtension(String name) { Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } injectExtension(instance); Set<Class<?>> wrapperClasses = cachedWrapperClasses; // cache中是否存在wrapper类,如果存在,遍历,最后返回wrapper这个实例 if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class<?> wrapperClass : wrapperClasses) { // 注册扩展,返回 wrapperClass.getConstructor(type).newInstance(instance) 实例 instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type + ") could not be instantiated: " + t.getMessage(), t); } }
private T injectExtension(T instance) { try { if (objectFactory != null) { for (Method method : instance.getClass().getMethods()) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { Class<?> pt = method.getParameterTypes()[0]; try { String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; Object object = objectFactory.getExtension(pt, property); if (object != null) { method.invoke(instance, object); } } catch (Exception e) { logger.error("fail to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; }
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper mock=com.alibaba.dubbo.rpc.support.MockProtocol
public class ServiceConfig<T> extends AbstractServiceConfig { private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); @SuppressWarnings({"unchecked", "rawtypes"}) private void exportLocal(URL url) { if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { // 组装URL URL local = URL.valueOf(url.toFullString()) // 常量值为injvm,在执行wrapper链时用到 .setProtocol(Constants.LOCAL_PROTOCOL) .setHost(LOCALHOST) .setPort(0); ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref)); // protocol,Protocol$Adaptive Exporter<?> exporter = protocol.export( proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); exporters.add(exporter); logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); } } }
import com.alibaba.dubbo.common.extension.ExtensionLoader; public class Protocol$Adpative implements Protocol { public void destroy() { // throw Exception } public int getDefaultPort() { // throw Exception } public Invoker refer(Class arg0, URL arg1) throws RpcException { if (arg1 == null) throw new IllegalArgumentException("url == null"); URL url = arg1; String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) // throw Exception Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName); return extension.refer(arg0, arg1); } public Exporter export(Invoker arg0) throws RpcException { if (arg0 == null) // throw Exception if (arg0.getUrl() == null) // throw Exception URL url = arg0; String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) // throw Exception Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName); return extension.export(arg0); } }
通过如下两行代码
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); // dubbo Protocol extension = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
通过扩展名,我们可以在/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol 文件分析出
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper # Wrapper listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper # Wrapper mock=com.alibaba.dubbo.rpc.support.MockProtocol injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol # 在ServiceConfig 组装过这个协议名称 rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol com.alibaba.dubbo.rpc.protocol.http.HttpProtocol com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
在没有Wrapper的情况下,得到的扩展类为com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
public class ProtocolListenerWrapper implements Protocol { public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } return new ListenerExporterWrapper<T>(protocol.export(invoker), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class) .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY))); } }
public class ProtocolFilterWrapper implements Protocol { public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER)); } }
再接下来执行 injvm 对应的InjvmProtocol类中的export方法