[dubbo 源码之 ]1. 服务提供方如何发布服务 (2)

执行PROXY_FACTORY.getInvoker的时候实际上首先执行扩展接口ProxyFactory的适配类ProxyFactory$Adaptive的getInvoker方法,根据URL中参数proxy的设置类型选择具体的代理工厂,默认使用的是javassist,,因此又调用了org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker来获取代理实现类,代码如下:

/** * JavaassistRpcProxyFactory */ public class JavassistProxyFactory extends AbstractProxyFactory { ... @Override public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { // TODO Wrapper cannot handle this scenario correctly: the classname contains '$' // 这里使用javassist动态代理生成serviceImpl实现类的包装类`Wraaper...` 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); } }; } ... }

上面代码有2个目的:

inal Wrapper wrapper = Wrapper.getWrapper(...);用来生成具体serviceImpl的包装类,减少反射的性能损耗;

return new AbstractProxyInvoker<T>... 返回了一个抽象的代理invoker,并且重写了doInvoker方法,重写之后使用包装类中的invokeMethod来调用方法。

经过上述2步,服务提供方就将具体的实现类转换为Invoker代理。

然后,当执行protocol.export(),实际上也是调用了Protocol$Adaptive#export()方法,同时也分为两种情况

如果为远程暴露,则执行RegistryProtocol#export

如果为本地暴露,则只需InjvmProtocol#export

由于dubbo的增强SPI特性支持,injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));,则在调用之前会一层一层调用,ProtocolFilterWrapper->ProtocolListenerWrapper->QosProtocolWrapper,最后会调用export方法,此方法会将Invoker转换为Exporter对象,在org.apache.dubbo.registry.integration.RegistryProtocol#export方法中,org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport方法启NettyServer来监听服务,org.apache.dubbo.registry.integration.RegistryProtocol#register将当前的服务注册到注册中心。

doLocalExport 是如何启动NettyServer呢?

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) { String key = getCacheKey(originInvoker); return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> { Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl); return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker); }); }

此时URL中的protocol类型为默认的dubbo,因此会执行DubboProtocol#export进行转换,如下:

@Override public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl(); // export service. String key = serviceKey(url); // invoker->exporter DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //export an stub service for dispatching event Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT); Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false); if (isStubSupportEvent && !isCallbackservice) { String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY); if (stubServiceMethods == null || stubServiceMethods.length() == 0) { if (logger.isWarnEnabled()) { logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) + "], has set stubproxy support event ,but no stub methods founded.")); } } else { stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); } } //创建server openServer(url); //序列化提示 optimizeSerialization(url); return exporter; }

可以看到代码执行到openServer,因为key=getAddress()=ip+port,因此,同一台机器只会开启一个NettyServer.

private void openServer(URL url) { // find server. String key = url.getAddress(); //client can export a service which's only for server to invoke boolean isServer = url.getParameter(IS_SERVER_KEY, true); if (isServer) { ProtocolServer server = serverMap.get(key); if (server == null) { synchronized (this) { server = serverMap.get(key); if (server == null) { serverMap.put(key, createServer(url)); } } } else { // server supports reset, use together with override server.reset(url); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgpjz.html