接着上一节,我们达到doExportForlProtocol()方法的第四段,我们组装好了URL,现在我们需要根据具体的协议,进行服务暴露了!
第一个是封装成Wrapper中,
一,本地服务暴露
exportLocal(url),位于ServiceConfig类中
private void exportLocal(URL url) {
URL local = URLBuilder.from(url)
.setProtocol(LOCAL_PROTOCOL)
.setHost(LOCALHOST_VALUE)
.setPort(0)
.build();
//创建invoker 并到处服务,protocol允许的时候,会调用injvmProtocol的export 【入】
Exporter<?> exporter = PROTOCOL.export(
PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local)); //将[实例,接口,url],封装成url,然后进行暴露
exporters.add(exporter);
}
1.1 封装成Invoker
这个方法,我们调用的是ProxyFactory接口的实现类,先看一下顶层接口,
有两种方法,一个是获得proxy代理对象,代理的是invoker,还有一个是封装成为invoker对象,注意这里还使用spi,扩展点。
@SPI("javassist")
public interface ProxyFactory {
//create proxy.
@Adaptive({PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException;
//create proxy
@Adaptive({PROXY_KEY})
<T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
//create proxy
@Adaptive({PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
传入的三个参数依次:接口实现类,接口Class对象,URL
(默认是这个实现类):JavassistProxyFactory类: 工厂就是产生类的,产生的是Invoker类
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
//创建 匿名invoker对象,并且实现doInvoke方法
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);
}
};
}
这里调用了getWrapper(),我们在上一节中,有详细的讲述,它是dubbo自己实现的代理方式,返回了一个wrapper。
自然的,同等级的JdkProxyFactory 自然是使用jdk的动态代理,可以看一下代码:
public class JdkProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
Method method = proxy.getClass().getMethod(methodName, parameterTypes);
return method.invoke(proxy, arguments);
}
};
}
}
他们两个代理工厂都创建了 匿名的invoker对象,并且实现了doInvoke方法,两者的实现方式不同,可以理解,现在终于找到了invoker是的本质了,它就是对三者信息的封装。
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
private final T proxy;
private final Class<T> type;
private final URL url;
...
}
1.2 export(invoker)
来到InjvmProtocol类中
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
返回了一个暴露bean:InjvmExporter类,它是对一个暴露点的封装,使用serviceKey作为key,然后放入map中。key是这个类私有的,但是map是全部本地服务通用的!,存放在AbstractProtocol中
class InjvmExporter<T> extends AbstractExporter<T> {
private final String key;
private final Map<String, Exporter<?>> exporterMap;
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
super(invoker);
this.key = key;
this.exporterMap = exporterMap;
exporterMap.put(key, this);
}
@Override
public void unexport() {
super.unexport();
exporterMap.remove(key);
}
}
最后,将export添加到链表中,本地服务暴露结束。这里没有涉及到网络传输。
private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>(); //The exported services
二,导出服务到远程
RegistryProtocol类的export()方法
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
URL registryUrl = getRegistryUrl(originInvoker);
URL providerUrl = getProviderUrl(originInvoker);
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); //监听初始化
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//export invoker 【入】,导出服务 ★ 所谓到处就是,使用netty暴露服务,启动服务器; 所谓注册就是把信息放到zk上面,便于其他服务发现!
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// 注册 url
final Registry registry = getRegistry(originInvoker);
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// 是否延迟 发布
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
//--------- 注册服务 ★------------ 服务注册不是必须的,可以直连!
if (register) {
register(registryUrl, registeredProviderUrl);
}
registerStatedUrl(registryUrl, registeredProviderUrl, register);
//------ 订阅override 数据 -------------------
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
notifyExport(exporter);
return new DestroyableExporter<>(exporter);
}
进入:
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); //如果配置协议为dubbo,这里就会调用dubboProtocol中的export()
});
}
DubboProtocol类的export()
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// export service. 获取服务坐标
String key = serviceKey(url);
//创建 DubboExporter
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) {
}
}
// 启动服务器 ★
openServer(url);
optimizeSerialization(url);
return exporter;
}
启动服务器:
private void openServer(URL url) {
// 获取 host:port
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.reset(url);
}
}
}
创建服务实例:
private ProtocolServer createServer(URL url) {
url = URLBuilder.from(url)
// send readonly event when server closes, it's enabled by default
.addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
// 添加心跳检测到 url中
.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
.addParameter(CODEC_KEY, DubboCodec.NAME)
.build();
//获取server参数,默认为netty
String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
//通过spir检测是否存在server参数所代表的 ransporter扩展,不存在则抛出异常
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
}
ExchangeServer server;
try {
//创建ExhangeServer ★【入】
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
//获取 Client参数,可指定netty,mina
str = url.getParameter(CLIENT_KEY);
if (str != null && str.length() > 0) {
//获取所有的transporter实现类名称集合,
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
// 检测当前 Dubbo 所支持的 Transporter 实现类名称列表中,
// 是否包含 client 所表示的 Transporter,若不包含,则抛出异常
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return new DubboProtocolServer(server);
}
绑定入口:
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
//获取Exchanger 默认为 HeaderExchanger
//紧接着调用HeaderExchanger的Bind方法创建ExchangeServer实例
return getExchanger(url).bind(url, handler); //b【入】HeaderExchanger
}