如何把provider的invoker export出去:1)为原始对象加wrapper,生成invoker;2)给invoker加各种filter,启动监听服务;3)注册服务地址

以HelloService为例:

public interface HelloService {
String sayHello();
}
<dubbo:service interface="com.zhang.HelloService" ref="helloService" />

ServiceConfig和<dubbo:service>基本对应上了。

public interface ApplicationListener {
public void onApplicationEvent(ApplicationEvent event);
} public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, ApplicationContextAware, ApplicationListener, BeanNameAware {
public void onApplicationEvent(ApplicationEvent event) {
if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
if (isDelay()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
}
} public class ServiceConfig<T> extends AbstractServiceConfig {
private ProviderConfig provider;
// 是否暴露
protected Boolean export; private String interfaceName;
private Class<?> interfaceClass;
//即<dubbo:service>的ref对象
private T ref; public synchronized void export() {
if (provider != null) {
if (export == null) {
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
if (export != null && ! export.booleanValue()) {
return;
}
if (delay != null && delay > 0) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(delay);
} catch (Throwable e) {
}
doExport();
}
});
thread.setDaemon(true);
thread.setName("DelayExportServiceThread");
thread.start();
} else {
//关于export和delay的配置好像不怎么用,基本走else分支
doExport();
}
} protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("Already unexported!");
}
if (exported) {
return;
}
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
checkDefault();
if (provider != null) {
if (application == null) {
application = provider.getApplication();
}
if (registries == null) {
registries = provider.getRegistries();
}
if (monitor == null) {
monitor = provider.getMonitor();
}
if (protocols == null) {
protocols = provider.getProtocols();
}
}
if (application != null) {
if (registries == null) {
registries = application.getRegistries();
}
if (monitor == null) {
monitor = application.getMonitor();
}
}
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
generic = true;
} else {
try {
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
checkInterfaceAndMethods(interfaceClass, methods);
checkRef();
generic = false;
}
if(local !=null){
if(local=="true"){
local=interfaceName+"Local";
}
Class<?> localClass;
try {
localClass = Class.forName(local);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if(!interfaceClass.isAssignableFrom(localClass)){
throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName);
}
}
if(stub !=null){
if(stub=="true"){
stub=interfaceName+"Stub";
}
Class<?> stubClass;
try {
stubClass = Class.forName(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if(!interfaceClass.isAssignableFrom(stubClass)){
throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
checkApplication();
checkRegistry();
checkProtocol();
checkStubAndMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
doExportUrls();
exported = true;
}
}

一、生成invoker

ServiceConfig.doExportUrlsFor1Protocol 代码片段:

// ref就是原始对象
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass,
registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
// protocol是Protocol$Adpative
Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);

以javassist为例,默认从JavassistProxyFactory获取invoker,其实是生成wrapper。

// JavassistProxyFactory
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper类不能正确处理带$的类名。这里的 T proxy 是原始对象
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);
}
};
}

com.alibaba.dubbo.common.bytecode.Wrapper.makeWrapper(Class<?> c) 方法中生成wrapper类,代码格式化后如下:

public class com.alibaba.dubbo.common.bytecode.Wrapper1 extends Wrapper {
public static String[] pns = null;
public static Map pts = null;
public static String[] mns = { "sayHello" };
public static String[] dmns = { "sayHello" };
public static Class[] mts0 = null; public String[] getPropertyNames() {
return pns;
} public boolean hasProperty(String n) {
return pts.containsKey($1);
} public Class getPropertyType(String n) {
return (Class) pts.get($1);
} public String[] getMethodNames() {
return mns;
} public String[] getDeclaredMethodNames() {
return dmns;
} public void setPropertyValue(Object o, String n, Object v) {
com.zhang.HelloServiceImpl w;
try {
w = ((com.zhang.HelloServiceImpl) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException(
"Not found property \""
+ $2
+ "\" filed or setter method in class com.zhang.HelloServiceImpl.");
} public Object getPropertyValue(Object o, String n) {
com.zhang.HelloServiceImpl w;
try {
w = ((com.zhang.HelloServiceImpl) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException(
"Not found property \""
+ $2
+ "\" filed or setter method in class com.zhang.HelloServiceImpl.");
} public Object invokeMethod(Object o, String n, Class[] p, Object[] v)
throws java.lang.reflect.InvocationTargetException {
com.zhang.HelloServiceImpl w;
try {
w = ((com.zhang.HelloServiceImpl) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
try {
if ("sayHello".equals($2) && $3.length == 0) {
return ($w) w.sayHello();
}
} catch (Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException(
"Not found method \"" + $2
+ "\" in class com.zhang.HelloServiceImpl.");
}
}

二、开始export。贴出Protocol$Adpative的代码,重点关注export方法:

package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException(
"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
} public int getDefaultPort() {
throw new UnsupportedOperationException(
"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
} public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0,
com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
if (arg1 == null)
throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
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.refer(arg0, arg1);
} 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();
// 根据invoker的url,获取扩展名
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);
}
} package com.alibaba.dubbo.rpc.cluster;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Cluster$Adpative implements com.alibaba.dubbo.rpc.cluster.Cluster {
public com.alibaba.dubbo.rpc.Invoker join(
com.alibaba.dubbo.rpc.cluster.Directory arg0)
throws com.alibaba.dubbo.rpc.cluster.Directory {
if (arg0 == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.cluster.Directory argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException(
"com.alibaba.dubbo.rpc.cluster.Directory argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("cluster", "failover");
if (extName == null)
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.cluster.Cluster) name from url("
+ url.toString() + ") use keys([cluster])");
com.alibaba.dubbo.rpc.cluster.Cluster extension = (com.alibaba.dubbo.rpc.cluster.Cluster) ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.cluster.Cluster.class)
.getExtension(extName);
// extension是MockClusterWrapper
return extension.join(arg0);
}
}

从调用栈中能看出,Protocol$Adpative.export调用了两次,在Protocol$Adpative的export函数内部,
第一次获取的protocol是 ProtocolListenerWrapper/ProtocolFilterWrapper/RegistryProtocol,
第二次获取的protocol是 ProtocolListenerWrapper/ProtocolFilterWrapper/DubboProtocol。

第一次:ServiceConfig.doExportUrlsFor1Protocol代码片段:

if (registryURLs != null && registryURLs.size() > 0
&& url.getParameter("register", true)) {
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
// 获取invoker
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
// protocol是Protocol$Adpative
// invoker的url:registry://127.0.0.1:2181/xxxxx
Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
}

第二次 RegistryProtocol:

// RegistryProtocol
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker){
String key = getCacheKey(originInvoker);
ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
synchronized (bounds) {
exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
final Invoker<?> invokerDelegete =
new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
//protocol是com.alibaba.dubbo.rpc.Protocol$Adpative
// invoker的url:dubbo://192.168.233.6:20880
exporter = new ExporterChangeableWrapper<T>((Exporter<T>)protocol.export(invokerDelegete), originInvoker);
bounds.put(key, exporter);
}
}
}
return (ExporterChangeableWrapper<T>) exporter;
}

暴露服务主要的步骤可能在这儿了:

// RegistryProtocol
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//export invoker 开启服务
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
//registry provider 注册服务
final Registry registry = getRegistry(originInvoker);
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
registry.register(registedProviderUrl);
// 订阅override数据
// FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//保证每次export都返回一个新的exporter实例
return new Exporter<T>() {
public Invoker<T> getInvoker() {
return exporter.getInvoker();
}
public void unexport() {
try {
exporter.unexport();
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
registry.unregister(registedProviderUrl);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
overrideListeners.remove(overrideSubscribeUrl);
registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
}
};
}

在DubboProtocol中export,主要是启动服务:

// DubboProtocol
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl(); // export service.
String key = serviceKey(url);
//DubboExporter封装了invoker,invoker对象是RegistryProtocol$InvokerDelegete
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
//把exporter放入map中
//key: a/com.zhang.HelloService:20880
//value: DubboExporter
exporterMap.put(key, exporter); //export an stub service for dispaching event
Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice){
String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0 ){
if (logger.isWarnEnabled()){
logger.warn(new IllegalStateException("consumer [" +url.getParameter(Constants.INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
} openServer(url); return exporter;
} private void openServer(URL url) {
// find server.
String key = url.getAddress();
//client 也可以暴露一个只有server可以调用的服务。
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
serverMap.put(key, createServer(url));
} else {
//server支持reset,配合override功能使用
server.reset(url);
}
}
}
private ExchangeServer createServer(URL url) {
//默认开启server关闭时发送readonly事件
url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
//默认开启heartbeat
url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
throw new RpcException("Unsupported server type: " + str + ", url: " + url); url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME);
ExchangeServer server;
try {
//requestHandler是DubboProtocol的一个内部类(ExchangeHandlerAdapter)
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
str = url.getParameter(Constants.CLIENT_KEY);
if (str != null && str.length() > 0) {
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}

绑定requestHandler

// Exchangers
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");
return getExchanger(url).bind(url, handler);
} // HeaderExchanger
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

dubbo provider如何对invoker进行export的更多相关文章

  1. Nodejs“实现”Dubbo Provider

    背景 目前nodejs应用越来越广泛,但和java的dubbo体系接入困难,所以我们需要实现node端的dubbo provider逻辑.java的dubbo provider是和consumer在一 ...

  2. dubbo.provider和dubbo.consumer配置

    Configure service provider <?xml version="1.0" encoding="UTF-8"?> <bean ...

  3. Apache Dubbo Provider默认反序列漏洞复现(CVE-2020-1948)

    Apache Dubbo Provider默认反序列漏洞(CVE-2020-1948) 0x01 搭建漏洞环境 漏洞介绍 2020年06月23日, 360CERT监测发现Apache Dubbo 官方 ...

  4. 【CVE-2020-1948】Apache Dubbo Provider反序列化漏洞复现

    一.实验简介 实验所属系列: 系统安全 实验对象:本科/专科信息安全专业 相关课程及专业: 计算机网络 实验时数(学分):2 学时 实验类别: 实践实验类 二.实验目的 Apache Dubbo是一款 ...

  5. dubbo源码—service export

    在应用编写好服务并进行之后,dubbo负责将服务export出去,dubbo export服务的时候主要做了以下几件事: 将服务export到本地(根据scope的配置) 创建Invoker(启动本地 ...

  6. Dubbo实践(十三)Export

    Spring在启动Dubbo服务端应用时,会实例化ServiceBean<T>并设置配置属性,然后调用export方法: @SuppressWarnings({"unchecke ...

  7. dubbo源码分析14——DubboProtocol的export方法分析

    走到了这一步也挺不容易的,把之前的暴露入口代码再列出来回顾一下: //配置为none不暴露 if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase ...

  8. 【dubbo】dubbo项目基本结构及provider构建

    dubbo项目基本结构如下,分别部署于不同服务器: 1.provider(接口API 实现) 2.consumer(web) 3.zookeeper 4.DB provider构建 1.api构建 i ...

  9. Dubbo源码学习--服务发布(ProxyFactory、Invoker)

    上文分析了Dubbo服务发布的整体流程,但服务代理生成的具体细节介绍得还不是很详细.下面将会接着上文继续分析.上文介绍了服务代理生成的切入点,如下: Invoker<?> invoker ...

随机推荐

  1. 20145322何志威 Exp7 网络欺诈技术防范

    20145322何志威 Exp7 网络欺诈技术防范 一 实践过程记录 简单应用SET工具建立冒名网站 1 确保kali和靶机能ping通: 2 为了使得apache开启后,靶机通过ip地址可以直接访问 ...

  2. 洛谷月赛 Hello World(升级版) - 动态规划

    题目背景 T1答案要mod1000000007(10^9+7),请重新提交,非常抱歉! 一天,智障的pipapi正在看某辣鸡讲义学程序设计. 题目描述 在讲义的某一面,他看见了一篇文章.这篇文章由英文 ...

  3. updateByPrimaryKeySelective更新失败

    问题:使用Mybatis中Mapper内置方法updateByPrimaryKeySelective更新失败. 发现:控制台打印出来的sql语句发现where条件出现所有属性. 解决:映射的实体类没有 ...

  4. 设置控件如ImageButton可见与否

    继承view的控件有三种ui属性: 1.setVisibility(View.Gone); 不可见,不占有空间 2.setVisibility(View.VISIBLE); 可见 3.setVisib ...

  5. Hexo 搭建 Blog 精简笔记

    安装Hexo npm install -g hexo-cli Mac 用户 您在编译时可能会遇到问题,请先到 App Store 安装 Xcode,Xcode 完成后,启动并进入 Preference ...

  6. Windows下卸载软件时提示 等待先前的卸载完成? 终止 dllhost.exe 进程

    只要结束进程中的 "dllhost" 进程就好了. 估计原因是, 当卸载某些 "所谓的"较大型的软件的时候, 要去更新, 更改系统对dll链接库的注册, 更新. ...

  7. 【分词器及自定义】Elasticsearch中文分词器及自定义分词器

    中文分词器 在lunix下执行下列命令,可以看到本来应该按照中文”北京大学”来查询结果es将其分拆为”北”,”京”,”大”,”学”四个汉字,这显然不符合我的预期.这是因为Es默认的是英文分词器我需要为 ...

  8. [BZOJ4027][HEOI2015]兔子与樱花 树形dp

    Description 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接 ...

  9. Vue项目中使用Vuex + axios发送请求

    本文是受多篇类似博文的影响写成的,内容也大致相同.无意抄袭,只是为了总结出一份自己的经验. 一直以来,在使用Vue进行开发时,每当涉及到前后端交互都是在每个函数中单独的写代码,这样一来加大了工作量,二 ...

  10. 【Python】【 接口自动化测试】【一】环境搭建

    1. 环境配置 我电脑Windows7 64位  +  Python2.7  + Oracle客户端 10.2 + cx_Oracle 10g Oracle客户端下载(为此我还申请个Oracle账号) ...