在dubbo中,万物皆是Invoker,即便是Exporter也是由Invoker进化而成的
那么Invoker到底是什么鬼
在 Dubbo 的核心领域模型中:
Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。
Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。
Dubbo协议下的执行流程图
主要分析一下DubboInvoker
的源码
public interface Invoker extends Node {
/**
* get service interface.
*
* @return service interface.
*/
Class getInterface();
/**
* invoke.
*
* @param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
}
public abstract class AbstractInvoker implements Invoker {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final Class type;
private final URL url;
private final Map attachment;
private volatile boolean available = true;
private AtomicBoolean destroyed = new AtomicBoolean(false);
public AbstractInvoker(Class type, URL url) {
this(type, url, (Map) null);
}
public AbstractInvoker(Class type, URL url, String[] keys) {
this(type, url, convertAttachment(url, keys));
}
public AbstractInvoker(Class type, URL url, Map attachment) {
if (type == null)
throw new IllegalArgumentException("service type == null");
if (url == null)
throw new IllegalArgumentException("service url == null");
this.type = type;
this.url = url;
this.attachment = attachment == null ? null : Collections.unmodifiableMap(attachment);
}
private static Map convertAttachment(URL url, String[] keys) {
if (keys == null || keys.length == 0) {
return null;
}
Map attachment = new HashMap();
for (String key : keys) {
String value = url.getParameter(key);
if (value != null && value.length() > 0) {
attachment.put(key, value);
}
}
return attachment;
}
public Class getInterface() {
return type;
}
public URL getUrl() {
return url;
}
public boolean isAvailable() {
return available;
}
protected void setAvailable(boolean available) {
this.available = available;
}
public void destroy() {
if (!destroyed.compareAndSet(false, true)) {
return;
}
setAvailable(false);
}
public boolean isDestroyed() {
return destroyed.get();
}
public String toString() {
return getInterface() + " -> " + (getUrl() == null ? "" : getUrl().toString());
}
public Result invoke(Invocation inv) throws RpcException {
if (destroyed.get()) {
throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost()
+ " use dubbo version " + Version.getVersion()
+ " is DESTROYED, can not be invoked any more!");
}
RpcInvocation invocation = (RpcInvocation) inv;
invocation.setInvoker(this);
if (attachment != null && attachment.size() > 0) {
invocation.addAttachmentsIfAbsent(attachment);
}
Map context = RpcContext.getContext().getAttachments();
if (context != null) {
invocation.addAttachmentsIfAbsent(context);
}
if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
}
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
try {
// 调用逻辑
return doInvoke(invocation);
} catch (InvocationTargetException e) { // 包装各种异常 biz exception
Throwable te = e.getTargetException();
if (te == null) {
return new RpcResult(e);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
return new RpcResult(te);
}
} catch (RpcException e) {
if (e.isBiz()) {
return new RpcResult(e);
} else {
throw e;
}
} catch (Throwable e) {
return new RpcResult(e);
}
}
protected abstract Result doInvoke(Invocation invocation) throws Throwable;
}
public class DubboInvoker<T> extends AbstractInvoker<T> {
private final ExchangeClient[] clients;
private final AtomicPositiveInteger index = new AtomicPositiveInteger();
private final String version;
private final ReentrantLock destroyLock = new ReentrantLock();
private final Set> invokers;
public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients) {
this(serviceType, url, clients, null);
}
/**
* 构造方法
*/
public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients, Set> invokers) {
super(serviceType, url, new String[]{Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY});
this.clients = clients;
// get version.
this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0");
this.invokers = invokers;
}
/**
* 真正的远程调用逻辑
*/
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
inv.setAttachment(Constants.VERSION_KEY, version);
// 传输端的客户端
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
// 是否异步
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
// 是否返回值,也就是相当于发送了一个指令,不在乎服务端的返回
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
if (isOneway) { // 无论同步、异步,只发送指令
// sent="true" 等待消息发出,消息发送失败将抛出异常。
// sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
// 客户端发送请求
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture(null);
return new RpcResult();
} else if (isAsync) { // 异步调用
// 发送请求,并返回future
ResponseFuture future = currentClient.request(inv, timeout);
// 设置future
RpcContext.getContext().setFuture(new FutureAdapter
看完这个逻辑,就能理解这句话了
而 Remoting 实现是 Dubbo 协议的实现,如果你选择 RMI 协议,整个 Remoting 都不会用上,
Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层,
Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,
它也可以扩展 UDP 传输,而 Exchange 层是在传输层之上封装了 Request-Response 语义。
因为实现RMI,不再需要通过remoting传输消息层了,因为 Remoting 实现是 Dubbo 协议的实现
,RMI有自己的传输机制和方法调用机制,
详细看RmiProtocol
protected T doRefer(final Class serviceType, final URL url) throws RpcException {
final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
// RMI needs extra parameter since it uses customized remote invocation object
if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getVersion()).equals(Version.getVersion())) {
// Check dubbo version on provider, this feature only support
rmiProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() {
public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
// 执行器
return new RmiRemoteInvocation(methodInvocation);
}
});
}
rmiProxyFactoryBean.setServiceUrl(url.toIdentityString());
rmiProxyFactoryBean.setServiceInterface(serviceType);
rmiProxyFactoryBean.setCacheStub(true);
rmiProxyFactoryBean.setLookupStubOnStartup(true);
rmiProxyFactoryBean.setRefreshStubOnConnectFailure(true);
rmiProxyFactoryBean.afterPropertiesSet();
return (T) rmiProxyFactoryBean.getObject();
}
com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation
@Override
public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
RpcContext context = RpcContext.getContext();
context.setAttachments((Map) getAttribute(dubboAttachmentsAttrName));
try {
return super.invoke(targetObject);
} finally {
context.setAttachments(null);
}
}
org.springframework.remoting.support.RemoteInvocation
/**
* Perform this invocation on the given target object.
* Typically called when a RemoteInvocation is received on the server.
* @param targetObject the target object to apply the invocation to
* @return the invocation result
* @throws NoSuchMethodException if the method name could not be resolved
* @throws IllegalAccessException if the method could not be accessed
* @throws InvocationTargetException if the method invocation resulted in an exception
* @see java.lang.reflect.Method#invoke
*/
public Object invoke(Object targetObject)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);
return method.invoke(targetObject, this.arguments);
}
直接通过java的反射执行,因为spring已经实现了RMI,即已经把这些事情做了。
看下来就发现了真正和Invoker绑定在一起的就是Protocol的doExport和doRefer这两个方法,而Invoker无非就是一个类,或者说一种作用域,有了它,很多事情都方便了,在固定的层次上做固定的事情。
回顾一下接口
/Invoker/
/**
* get service interface.
*
* @return service interface.
*/
Class getInterface();
/**
* invoke.
*
* @param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
/ Node ///
/**
* get url.
*
* @return url.
*/
URL getUrl();
/**
* is available.
*
* @return available.
*/
boolean isAvailable();
/**
* destroy.
*/
void destroy();