文章目录

  • ​​ServiceBean对象暴露服务​​
  • ​​injvm协议​​
  • ​​Invoker构建​​
  • ​​exportor暴露​​
  • ​​远程暴露​​
  • ​​总结​​
  • ​​扩展点​​
  • ​​Protocol$Adaptive 源码​​
  • ​​ProxyFactory$Adaptive源码​​

ServiceBean对象暴露服务

  • 服务暴露一般包括本地暴露和远程暴露
  • 本地暴露的协议为injvm,远程暴露的协议为registry+dubbo对应的协议类分别为InjvmProtocol和RegistryProtocol+DubboProtocol
  • Protocol$Adaptive进行export时,根据URL上的protocol值取协议实现类,如果无该参数则默认dubbo

本地暴露 URL为injvm协议

远程暴露url协议一dubbo协议

远程暴露ur协议二registry协议

injvm://127.0.0.1/com.renxl.demo.UserService?anyhost=true&application=dubbo-demo&…

dubbo://192.168.2.103:19012/com.renxl.demo.UserService?anyhost=true&…

registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?..

String scope = url.getParameter(SCOPE_KEY);
SCOPE_NONE是字符串“none”,一般这里为空
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
step-1: 进行本地暴露
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
exportLocal(url);
}

if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
进行注册中心暴露
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
...... 删除其他代码
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
}

String proxy = url.getParameter(PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(PROXY_KEY, proxy);
}
step-2: 构建Invoker
registryURL为远程暴露协议二
url为远程暴露协议一
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
step-3: 远程服务暴露
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
...... 删除无注册中心情况


}
}

injvm协议

- 构建的url采用injvm协议 
- 构建Invoker并暴露到exportermap
- 加入exporters用于管控销毁
private void exportLocal(URL url) {
url如下:
injvm://127.0.0.1/com.renxl.demo.UserService?anyhost=true&application=dubbo-demo&......
URL local = URLBuilder.from(url)
采用injvm协议
.setProtocol(LOCAL_PROTOCOL)
.setHost(LOCALHOST_VALUE)
.setPort(0)
.build();
Exporter<?> exporter = protocol.export(
PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
加入servicebean的exporters,一般包括本地和远程
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
}

Invoker构建

  • 创建Invoker对象,用于内部方法调用
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {

final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
根据参数调用目标对象目标方法
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}

exportor暴露

  • 结合扩展点以及前文知道
  • 这里为Protocoldubbo源码分析第六篇一服务暴露第二小节一Invoker构建与exportor暴露_后端Adaptive获取InjvmProtocol对象,由于spi机制存在wrapper能力,所以InjvmProtocol被ProtocolListenerWrapper和ProtocolFilterWrapper包装
protocol.export(
PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
  • ProtocolListenerWrapper主要是构建根据url上exporter.listener构建监听器,监听服务unexport事件
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (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(), EXPORTER_LISTENER_KEY)));
}
  • ProtocolFilterWrapper主要是构建dubbofilter链
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
忽略register协议
if (REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
构建filter链
return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
}
  • injvmProtocol暴露的本质就是构建持有Invoker的Exporter对象,并加入exporterMap
  • exporterMap在将来发生通信,就是根据相应参数从exporterMap找对应的exporter,在获取其内部的Invoker进行方法调用
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}

远程暴露

  • 构建Invoker url为register协议
  • 暴露链路如下,具体实现参见第七小节

Protocol$Adaptive => ProtocolFilterWrapper => ProtocolListenerWrapper => RegistryProtocol

RegistryProtocol又会拿url参数对应的dubbo协议在进行一次暴露
Protocol$Adaptive => ProtocolFilterWrapper => ProtocolListenerWrapper => DubboProtocol

registryURL如下: registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?..
url如下: dubbo://192.168.2.103:19012/com.renxl.demo.UserService?anyhost=true&......

同injvm创建Invoker,不同的是协议registryURL为register:// 而url.toFullString()作为一个参数加入不同的是协议registryURL
url参数是一个dubbo协议,RegisterProtocol会通过这个url调用DubboProtocol
也就是说protocol.export(wrapperInvoker)先调用RegisterProtocol进行暴露

Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);

总结

  • SPI的应用: Protocol$Adaptive根据url上protocol获取对应实现类进行服务暴露
  • SPI的应用: Protocol$Adaptive获取具体协议进行暴露,都会调用Wrapper完成监听,过滤等功能(内部判断如果是register协议则忽略)
  • 服务的暴露一般分远程和本地,暴露完毕添加到exporterMap,用于将来服务调用时进行查找
  • exporterMap的key,如果是本地为接口名,远程为接口名加端口号

本地

远程

com.renxl.demol.UserService

com.renxl.demol.UserService:19283

扩展点

Protocol$Adaptive 源码

  • 自适应协议扩展类进行export时,根据URL上的protocol值取协议实现类,如果无该参数则默认dubbo
public class Protocol$Adaptive implements Protocol {
public void destroy() {
throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}

public int getDefaultPort() {
throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}

public Exporter export(Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
Protocol extension = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.export(arg0);
}

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 new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
Protocol extension = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}

ProxyFactory$Adaptive源码

ProxyFactory$Adaptive 默认取javassist

public class ProxyFactory$Adaptive implements  ProxyFactory {
public Object getProxy( Invoker arg0) throws RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
ProxyFactory extension = (ProxyFactory) ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0);
}

public Object getProxy(Invoker arg0, boolean arg1) throws RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
ProxyFactory extension = (ProxyFactory) ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0, arg1);
}

public Invoker getInvoker(Object arg0, java.lang.Class arg1, URL arg2) throws org.apache.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
ProxyFactory extension = (ProxyFactory) ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
}