在启动dubbo服务的时候我们可以看到这样一些日志
第一行代码表示dubbo服务在 spring启动之后准备开始启动了,这行代码定位到
ServiceBean#onApplicationEvent()中
这个方法在spring启动过程的refresh方法中会执行到,具体可以看我spring系列文章
这里关注this.export();
直接定位到
ServiceConfig#this.doExport();
---->this.doExportUrls();
private void doExportUrls() { ListregistryURLs = this.loadRegistries(true); Iterator i$ = this.protocols.iterator(); while(i$.hasNext()) { ProtocolConfig protocolConfig = (ProtocolConfig)i$.next(); this.doExportUrlsFor1Protocol(protocolConfig, registryURLs); } }
首先获取到URL,然后遍历所有的Protocol实例
这里只有一个dubbo
进入doExportUrlsFor1Protocol
前面都是一些检查和封装,我们直接找关键语句
if (!"none".toString().equalsIgnoreCase(scope)) { if (!"remote".toString().equalsIgnoreCase(scope)) { this.exportLocal(url); } if (!"local".toString().equalsIgnoreCase(scope)) { if (logger.isInfoEnabled()) { logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url); } if (registryURLs != null && registryURLs.size() > 0 && url.getParameter("register", true)) { Iterator i$ = registryURLs.iterator(); while(i$.hasNext()) { URL registryURL = (URL)i$.next(); url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic")); URL monitorUrl = this.loadMonitor(registryURL); if (monitorUrl != null) { url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString()); } if (logger.isInfoEnabled()) { logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL); } Invoker> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString())); Exporter> exporter = protocol.export(invoker); this.exporters.add(exporter); } } else { Invoker> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, url); Exporter> exporter = protocol.export(invoker); this.exporters.add(exporter); } } } this.urls.add(url);
这里会根据url上scope上的是否为none来进行本地暴露和远程暴露,我们先看本地暴露
this.exportLocal(url);
URL local = URL.valueOf(url.toFullString()).setProtocol("injvm").setHost("127.0.0.1").setPort(0); Exporter> exporter = protocol.export(proxyFactory.getInvoker(this.ref, this.interfaceClass, local)); this.exporters.add(exporter);
首先会吧协议变成injvm,然后获取一个invoker,吧这个invoker对象封装成一个exporter,最后吧这个exporter放在exporters集合中。其中第二句话是关键
proxyFactory.getInvoker(this.ref, this.interfaceClass, local)先看这句,这里会从proxyFactory中获取到一个invoker对象
在ServiceConfig的常量中有一个proxyFactory
private static final ProxyFactory proxyFactory = (ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
主意到ProxyFactory借口的实现类上没有标注@adatpive注解的类,所以
proxyFacotry是一个ProxyFacotry$Adaptive
public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws java.lang.Object { if (arg2 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg2; String extName = url.getParameter("proxy", "javassist"); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])"); com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getInvoker(arg0, arg1, arg2); }
复制出getInvoker方法
这里的extName=javassist
extension=JavassistProxyFactory,这里会调用JavassistProxyFactory的getInvoker方法
publicInvoker getInvoker(T proxy, Class type, URL url) { final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(36) < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker (proxy, type, url) { protected Object doInvoke(T proxy, String methodName, Class>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; }
首先获取到一个wrapper,关于这个wrapper
Wrapper是一个独立的抽象类, 用来 包装对接口class的操作(上面我们说的IUserService)。这里对class操作,我们可以抽象几种操作:
1.获取class中所有字段的名称 : abstract public String[] getPropertyNames();
2.根据字段名称获取字段类型:abstract public Class getPropertyType(String pn);
3.判断class中是否存在某字段:abstract public boolean hasProperty(String name);
4.获取class对象的某字段的值:abstract public Object getPropertyValue(Object instance, String pn) throws Throwable;
5.设置字段的值:abstract public void setPropertyValue(Object instance, String pn, Object pv) throws Throwable;
6.执行方法:abstract public Object invokeMethod(Object instance, String methodName, Class[] types, Object[] args) throws Throwable;
然后我们说一下AbstractProxyInvoker,AbstractProxyInvoker继承Invoker接口
public interface Invoker
// 执行方法, Invocation 为执行信息(包括执行 哪个方法,参数等信息),Result为执行结果
Result invoker(Invocation invocation);
// 省略其它 dubbo中的方法
}
点击进入invocation public interface Invocation { String getMethodName(); ----------方法名称 Class>[] getParameterTypes(); -----------------方法参数类型 Object[] getArguments(); -----------方法参数 //忽略 }
Result对象中封装了返回的结果
package com.alibaba.dubbo.rpc.proxy; import java.lang.reflect.InvocationTargetException; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcResult; /** * InvokerWrapper * * @author william.liangf */ public abstract class AbstractProxyInvokerimplements Invoker { private final T proxy; private final Class type; private final URL url; public AbstractProxyInvoker(T proxy, Class type, URL url){ if (proxy == null) { throw new IllegalArgumentException("proxy == null"); } if (type == null) { throw new IllegalArgumentException("interface == null"); } if (! type.isInstance(proxy)) { throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type); } this.proxy = proxy; this.type = type; this.url = url; } 。。。。。。 public Result invoke(Invocation invocation) throws RpcException { try { return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments())); } catch (InvocationTargetException e) { return new RpcResult(e.getTargetException()); } catch (Throwable e) { throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e); } } protected abstract Object doInvoke(T proxy, String methodName, Class>[] parameterTypes, Object[] arguments) throws Throwable; 。。。。。 }
protected abstract Object doInvoke是一个模板方法,后续很多invoker都会实现这个方法
proxy=接口的实现类
type=接口名称
invoker方法就是真正实现调用的方法
关于这一块,可以参考这篇文章https://blog.csdn.net/LuoZheng4698729/article/details/80111714
https://blog.csdn.net/prestigeding/article/details/80642774
回到protocol.export
这个protocol是protocol$Adaptive
复制export方法
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker { if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl(); String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0); }
这里的extName=injvm
我们进入这里获取到的extension 是ProtocolFilterWrapper,至于原因可以参考dubbo 内核aop那一篇
进入到ProtocolFilterWrapper#export
buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER);
关于dubbo中filter的实现可以参考https://www.jianshu.com/p/d279349435cd
点击进入ExtensionLoader#getActivateExtension
public ListgetActivateExtension(URL url, String[] values, String group) { List exts = new ArrayList (); List names = values == null ? new ArrayList (0) : Arrays.asList(values); if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { getExtensionClasses(); for (Map.Entry entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); if (isMatchGroup(group, activate.group())) { T ext = getExtension(name); if (! names.contains(name) && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) { exts.add(ext); } } } Collections.sort(exts, ActivateComparator.COMPARATOR); } 在这里是加载dubbo自带的Filter,也就是@Activate修饰的 ------------------------------------ 下面开始是自己实现的Filter List usrs = new ArrayList (); for (int i = 0; i < names.size(); i ++) { String name = names.get(i); if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX) && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { if (Constants.DEFAULT_KEY.equals(name)) { if (usrs.size() > 0) { exts.addAll(0, usrs); usrs.clear(); } } else { T ext = getExtension(name); usrs.add(ext); } } } if (usrs.size() > 0) { exts.addAll(usrs); } return exts; }
回到buildInvokerChain方法,
private staticInvoker buildInvokerChain(final Invoker invoker, String key, String group) { Invoker last = invoker; List filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); if (filters.size() > 0) { for (int i = filters.size() - 1; i >= 0; i --) { final Filter filter = filters.get(i); final Invoker next = last; last = new Invoker () { public Class getInterface() { return invoker.getInterface(); } public URL getUrl() { return invoker.getUrl(); } public boolean isAvailable() { return invoker.isAvailable(); } public Result invoke(Invocation invocation) throws RpcException { return filter.invoke(next, invocation); } public void destroy() { invoker.destroy(); } @Override public String toString() { return invoker.toString(); } }; } } return last; }
最终换回的last中封装了所有的filter
回到ProtocolFilterWrapper
这里看到protocol依然是个装饰类,ProtocolListenerWrapper
进入ProtocolListenerWrapper#exprot方法
主要看
return new ListenerExporterWrapper(protocol.export(invoker), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class) .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
这里会返回一个ListenerExporterWrapper对象
这个ListenerExporterWrapper是封装过Listner和invoker得对象,invoker中又同时封装了Filter
回到ServiceConfig#exportLocal
exporters.add(exporter);
然后把这ListenerExporterWrapper加入到exporters集合中
如果我们自己实现这样一个Listner
public class MyExporterListener implements ExporterListener,InvokerListener { @Override public void exported(Exporter> exporter) throws RpcException { System.out.println("暴露" + exporter.getInvoker().getInterface()); } @Override public void unexported(Exporter> exporter) { } @Override public void referred(Invoker> invoker) throws RpcException { System.out.println("被引用"); } @Override public void destroyed(Invoker> invoker) { } }
那么这个时候日志会打印出 "暴露interface spi.Hello"
这时候本地暴露的代码已经分析完毕了
看到console上会打印出
DUBBO] Export dubbo service spi.Hello to local registry, dubbo version: 2.5.3, current host: 127.0.0.1
下一篇我们分析远程暴露