三Dubbo服务暴露源码分析--2本地暴露
三Dubbo服务暴露源码分析--2本地暴露
3.1 本地暴露(exportLocal)
ServiceConfig
private void exportLocal(URL url) {
//url中protocol如果不为injvm,重新设置URL为injvm://的协议头
if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
//转换前 dubbo://192.168.0.101:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-provider&dubbo=2.5.3&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=20987&side=provider×tamp=1671167576621
//injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-provider&dubbo=2.5.3&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=20987&side=provider×tamp=1671167576621
//将协议头更换为injvm;地址192.168.0.101:20880更换为127.0.0.1
URL local = URL.valueOf(url.toFullString())
.setProtocol(Constants.LOCAL_PROTOCOL)
.setHost(NetUtils.LOCALHOST)
.setPort(0);
//TAG1 getAdaptiveExtension(@SPI自适应)
//TAG2 proxyFactory.getInvoker---创建invoker
//TAG3 protocol.export---invoker转换为exporter
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() +" to local registry");
}
}
TAG1 getAdaptiveExtension(@SPI自适应)
此时,protocol的实现类是Dubbo机制创建的动态自适应类Protocol$Adpative。
ServiceConfig
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
@SPI("dubbo")
public interface Protocol {
/**
* 获取缺省端口,当用户没有配置端口时使用。
*
* @return 缺省端口
*/
int getDefaultPort();
/**
* 暴露远程服务:<br>
* 1. 协议在接收请求时,应记录请求来源方地址信息:RpcContext.getContext().setRemoteAddress();<br>
* 2. export()必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别。<br>
* 3. export()传入的Invoker由框架实现并传入,协议不需要关心。<br>
*
* @param <T> 服务的类型
* @param invoker 服务的执行体
* @return exporter 暴露服务的引用,用于取消暴露
* @throws RpcException 当暴露服务出错时抛出,比如端口已占用
*/
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
根据dubbo的@SPI机制,@Adaptive加在服务接口方法上,调用getAdaptiveExtension方法,会构建字节码,创建一个动态编译的adaptive类。
TAG1.1 Adaptive动态编译源码处理
将服务端log4j.xml配置文件内的log级别设置为DEBUG,
设置log4j的级别为debug原因,
此时,logger.debug会输出创建动态编译的adaptive的字节码。
然后再provider端的java文件夹下,创建对应的package,并复制console中输出的log信息,重建动态编译类,在方法调用处打断点,然后重启代码
TAG2 proxyFactory.getInvoker---ref服务转换invoker
//TAG1 getAdaptiveExtension(@SPI自适应)
//TAG2 proxyFactory.getInvoker---创建invoker
//TAG3 protocol.export---invoker转换为exporter
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
方法参数如上:
public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory {
public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg2;
//ProxyFactory的@spi拓展名为javassist
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])");
//TAG2.1 ProxyFactory自适应类--stubProxyFactoryWrapper
//创建ProxyFactory的javassist自适应类
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
//TAG2.2 proxyFactory.getInvoker
return extension.getInvoker(arg0, arg1, arg2);
}
}
TAG2.1 ProxyFactory自适应类--stubProxyFactoryWrapper(Wrapper机制)
@SPI("javassist")
public interface ProxyFactory {
/** create invoker.
*
* @param <T>
* @param proxy
* @param type
* @param url
* @return invoker
*/
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
ProxyFactory的方法上有@Adaptive({Constants.PROXY_KEY})标记,其会在执行getExtension(extName)时,创建动态编译类ProxyFactory$Adpative;其内代理方法,调用ExtensionLoader.getExtensionLoader.getExtension(extName)创建自适应实例。
这里,ProxyFactory为StubProxyFactoryWrapper,是@SPI的wrapper机制。
wrapper机制,会在JavassistProxyFactory加上包装
TAG2.2 JavassistProxyFactory.getInvoker
StubProxyFactoryWrapper
private final ProxyFactory proxyFactory;
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
return proxyFactory.getInvoker(proxy, type, url);
}
public class JavassistProxyFactory extends AbstractProxyFactory {
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper类不能正确处理带$的类名
//TAG2.2.1 Wrapper.getWrapper
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
//TAG2.2.2. AbstractProxyInvoker
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);
}
};
}
//TAG2.2.1 Wrapper.getWrapper--prov实例包装
将传入的服务端服务实例serviceImpl,字节码构造,并创建invokeMethod方法,调用服务时,根据方法名称遍历,执行最终调用。
详情看Wrapper.getWrapper的原理。
//TAG2.2.2. AbstractProxyInvoker--服务端本地暴露匿名类invoker
//invoker的包装类----invoker负责将对服务的调用,代理到invoker上的invoke方法
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
public Result invoke(Invocation invocation) throws RpcException {
try {
//调用invoke,返回RpcResult结果
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;
}
所以,服务本地暴露的匿名类AbstractProxyInvoker,重写doInvoke方法
//TAG2.2.2. AbstractProxyInvoker
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
//provider端invoker.invoke调用,代理到wrapper(ref实现类)的invokeMethod上
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
TAG3 Protocol$Adpative.export---invoker转换为exporter
//TAG1 getAdaptiveExtension(@SPI自适应)
//TAG2 proxyFactory.getInvoker---创建invoker
//TAG3 protocol.export---invoker转换为exporter
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
然后执行protocol.export(invoker),暴露服务,可知此时invoker实例为如下(AbstractProxyInvoker匿名类)
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws RpcException {
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");
//获取invoker内的服务的url
//injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-provider&dubbo=2.5.3&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=25677&side=provider×tamp=1671174564948
com.alibaba.dubbo.common.URL url = arg0.getUrl();
//protocol协议injvm
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])");
//TAG3.1 Protocol自适应类(listener、wrapper)
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
//TAG3.2 protocol.export
return extension.export(arg0);
}
TAG3.1 Protocol自适应类(listener、wrapper)
会再getExtension时,会先包裹filter,再包裹listener类
TAG3.2 listenerProtocol.export(listener->filter->injvm)
public class ProtocolListenerWrapper implements Protocol {
private final Protocol protocol;
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
//TAG3.2.1 filterprotocol.export
//TAG3.2.2 ListenerExporterWrapper
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
ProtocolListenerWrapper的export方法的作用,是当服务被protocol.export暴露后,创建ListenerExporterWrapper对象(该对象是exporter和ExporterListener的包装类,exporter是服务暴露的对象,由protocol.export(invoker)执行;ExporterListener是针对该exporter的监听器),protocol.export后,会执行其构造函数,会逐个的执行监听器的exposed方法--------上述过程,实现在服务被protocol.export暴露后,ExporterListener监听器执行相应的监听暴露exposed方法。
TAG3.2.1 filterprotocol.export
ProtocolFilterWrapper
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//如果protocol协议为registry,则直接protocol.export暴露--(registry表示需要注册,而不是构造拦截器链并export暴露)
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
//TAG3.2.1.1 buildInvokerChain
//TAG3.2.1.2 injvmProtocol.export
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
//TAG3.2.1.1 buildInvokerChain--构造拦截器链
方法参数:
ProtocolFilterWrapper
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//获取已经自动激活的filter对象
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
//倒序遍历filter,最后一个filter所构造的invoker,执行invoke时,是filter.invoke(next,invocation)。
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
/** ……………………………………………将filter构造为invoker拦截器链,其方法,获取都是当前abstractProxyInvoker匿名类的属性…………………………………………*/
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
/**………………………………………………………………………………………………………………………链式调用的实现………………………………………………………………………………………………………………………… */
public Result invoke(Invocation invocation) throws RpcException {
//倒序遍历filter,最后一个filter的执行,会调用filter.invoke(next,invocation),next为abstractProxyInvoker,则加入filter末尾
return filter.invoke(next, invocation);
}
};
}
}
return last;
}
注意上面构造filter链的顺序:
provider端的服务invoker----abstractProxyInvoker匿名类,加入filter的末尾,并返回头invoker。
active的filter如下:
构造后的拦截器链如下所示:
总结上面的filter链的构造,对服务的包裹结构,如下:
最内层的ref是provider端服务的实现类impl,由内到外是dubbo框架进行的包装。
//TAG3.2.1.2 injvmProtocol.export--暴露服务
ProtocolFilterWrapper
//TAG3.2.1.1 buildInvokerChain
//TAG3.2.1.2 injvmProtocol.export
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
在对abstractproxyInvoker包装上filter的invoker,并构成过滤器链后,执行protocol.export暴露服务。
public abstract class AbstractProtocol implements Protocol {
//在protocol中缓存exporter
protected final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>();
protected final Set<Invoker<?>> invokers = new ConcurrentHashSet<Invoker<?>>();
InjvmProtocol
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//TAG3.2.1.2.1 InjvmExporter(构造exporter对象)
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
//TAG3.2.1.2.1 InjvmExporter(构造exporter对象)
此时,构造InjvmExporter对象,并对exporter做缓存,存入exporterMap。传入的servicekey为当前provider服务接口,map中的value为暴露的exporter对象。
class InjvmExporter<T> extends AbstractExporter<T>
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap){
super(invoker);
this.key = key;
this.exporterMap = exporterMap;
//将服务接口为key;InjvmExporter为value,存入exporterMap中
exporterMap.put(key, this);
}
//exporter父类
public abstract class AbstractExporter<T> implements Exporter<T>
private final Invoker<T> invoker;
TAG3.2.2 ListenerExporterWrapper
然后回到TAG3.2过程中。在服务被protocol暴露后,会由ExporterListener监听器执行对应的监听方法。
public class ProtocolListenerWrapper implements Protocol {
//TAG3.2.1 filterprotocol.export
//TAG3.2.2 ListenerExporterWrapper
return new ListenerExporterWrapper<T>(protocol.export(invoker),
//unmodifiableList方法,返回内部列表的不可修改的list视图(只读)
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
//TAG3.2.2.1 getActivateExtension(ExtensionLoader机制)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
//TAG3.2.2.1 getActivateExtension(ExtensionLoader机制)
ExtensionLoader
public List<T> getActivateExtension(URL url, String key) {
return getActivateExtension(url, key, null);
}
此时,参数如下:
public List<T> getActivateExtension(URL url, String key, String group) {
//获取invoker.url内参数map内,key="exporter.listener",其value为对应的监听器名称
String value = url.getParameter(key);
return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
}
这里是,获取当前invoker.url上配置的key="exporter.listener",针对该特定invoker的监听器,而不是dubbo内的全部监听器。
//TAG3.2.2.2 ListenerExporterWrapper--监听exporter暴露并执行listener.exported通知
public class ListenerExporterWrapper<T> implements Exporter<T> {
private final Exporter<T> exporter;
private final List<ExporterListener> listeners;
//invoker在服务暴露后,执行构造函数,在实例化过程中,调用active激活状态的,且invoker.url内配置的所有ExporterListener的exporede方法
public ListenerExporterWrapper(Exporter<T> exporter, List<ExporterListener> listeners){
if (exporter == null) {
throw new IllegalArgumentException("exporter == null");
}
//传入暴露服务的exporter
this.exporter = exporter;
this.listeners = listeners;
if (listeners != null && listeners.size() > 0) {
RuntimeException exception = null;
//遍历当前invoker上配置的所有listener
for (ExporterListener listener : listeners) {
if (listener != null) {
try {
//当服务暴露时,执行listener的exported方法
listener.exported(this);
} catch (RuntimeException t) {
logger.error(t.getMessage(), t);
exception = t;
}
}
}
if (exception != null) {
throw exception;
}
}
}
invoker在服务暴露后,执行构造函数,在实例化过程中,调用active激活状态的,且invoker.url内配置的所有ExporterListener的exporede方法,达到protocol.export后,通知listener的作用。
TAG0 exportLocal
ServiceConfig
//服务端缓存当前暴露的服务Exporter的list列表
private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
private void exportLocal(URL url) {
if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
URL local = URL.valueOf(url.toFullString())
.setProtocol(Constants.LOCAL_PROTOCOL)
.setHost(NetUtils.LOCALHOST)
.setPort(0);
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() +" to local registry");
}
}
执行后exporters内对象如下: