作为一名从事幼教行业多年的从业者,我深知保育师资格证考试对职业发展的重要性。近年来,随着幼教行业规范化程度提高,保育师持证上岗已成为硬性要求。但现实情况是,很多在职保育员既要应对繁重的日常工作,又要抽时间备考,时间精力都十分有限。
传统备考方式存在明显痛点:
在这样的背景下,优质的刷题软件成为备考刚需。但市面上的题库产品良莠不齐,主要存在以下问题:
本文分享 Protocol 层。在 dubbo-rpc-api 模块,com.alibaba.dubbo.rpc.protocol 包下实现,如下图所示:

老艿艿:本文对应 《Dubbo 开发指南 —— 协议扩展》 文档。
com.alibaba.dubbo.rpc.Protocol ,协议接口。代码如下:
Java复制@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;
/**
* 引用远程服务:<br>
* 1. 当用户调用 refer() 所返回的 Invoker 对象的 invoke() 方法时,协议需相应执行同 URL 远端 export() 传入的 Invoker 对象的 invoke() 方法。<br>
* 2. refer() 返回的 Invoker 由协议实现,协议通常需要在此 Invoker 中发送远程请求。<br>
* 3. 当 url 中有设置 check=false 时,连接失败不能抛出异常,并内部自动恢复。<br>
*
* @param <T> 服务的类型
* @param type 服务的类型
* @param url 远程服务的URL地址
* @return invoker 服务的本地代理
* @throws RpcException 当连接服务提供方失败时抛出
*/
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
/**
* 释放协议:<br>
* 1. 取消该协议所有已经暴露和引用的服务。<br>
* 2. 释放协议所占用的所有资源,比如连接和端口。<br>
* 3. 协议在释放后,依然能暴露和引用新的服务。<br>
*/
void destroy();
}
@SPI("dubbo") 注解,Dubbo SPI 拓展点,默认为 "dubbo" 。@Adaptive 注解,基于 Dubbo SPI Adaptive 机制,加载对应的 Protocol 实现,使用 URL.protocol 属性。#getDefaultPort() 方法,获得协议的默认端口。#export(invoker) 方法,暴露远程服务。
#refer(type, url) 方法,引用远程服务。
#destroy() 方法,释放协议。在 JVM 关闭时,会被调用。com.alibaba.dubbo.rpc.protocol.AbstractProtocol ,实现 Protocol 接口,Protocol 抽象类。代码如下:
Java复制public abstract class AbstractProtocol implements Protocol {
/**
* Exporter 集合
*
* key: 服务键 {@link #serviceKey(URL)} 或 {@link URL#getServiceKey()} 。
* 不同协议会不同
*/
protected final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>();
// ... 省略和 Protocol 一致的方法,仅仅加了空实现。
protected static String serviceKey(URL url) {
return serviceKey(url.getPort(), url.getPath(), url.getParameter(Constants.VERSION_KEY), url.getParameter(Constants.GROUP_KEY));
}
protected static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) {
return ProtocolUtils.serviceKey(port, serviceName, serviceVersion, serviceGroup);
}
}
exporterMap 字段,Exporter 集合。其中,Key 通过 #serviceKey(URL) 方法,或者 URL#getServiceKey() 方法生成。不同协议会生成不同的格式,例如:
{group}/{path}:{version} 。{path}:{version} 。exporterMap 集合呢?因为一个服务,可以有多个协议,例如同时有 Dubbo 和 Hessian 两种协议。com.alibaba.dubbo.rpc.Invoker ,执行体接口。代码如下:
Java复制public interface Invoker<T> extends Node {
/**
* get service interface.
*
* 获得服务接口
*
* @return service interface.
*/
Class<T> getInterface();
/**
* invoke.
*
* 调用
*
* @param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
}
#getInterface() 方法,获得服务接口。在服务引用时,对应的服务的接口。#invoke(invocation) 方法,调用服务。在服务调用时,使用。com.alibaba.dubbo.rpc.protocol.AbstractInvoker ,实现 Invoker 接口,Invoker 抽象类。代码如下:
Java复制public abstract class AbstractInvoker<T> implements Invoker<T> {
private final Class<T> type;
private final URL url;
private final Map<String, String> attachment;
private volatile boolean available = true;
private volatile boolean destroyed = false;
public AbstractInvoker(Class<T> type, URL url) {
this(type, url, (Map<String, String>) null);
}
public AbstractInvoker(Class<T> type, URL url, String[] keys) {
this(type, url, convertAttachment(url, keys));
}
public AbstractInvoker(Class<T> type, URL url, Map<String, String> 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<String, String> convertAttachment(URL url, String[] keys) {
if (keys == null || keys.length == 0) {
return null;
}
Map<String, String> attachment = new HashMap<String, String>();
for (String key : keys) {
String value = url.getParameter(key);
if (value != null && value.length() > 0) {
attachment.put(key, value);
}
}
return attachment;
}
@Override
public Class<T> getInterface() {
return type;
}
@Override
public URL getUrl() {
return url;
}
@Override
public boolean isAvailable() {
return available;
}
protected void setAvailable(boolean available) {
this.available = available;
}
@Override
public void destroy() {
if (destroyed) {
return;
}
destroyed = true;
setAvailable(false);
}
public boolean isDestroyed() {
return destroyed;
}
@Override
public String toString() {
return getInterface() + " -> " + (getUrl() == null ? "" : getUrl().toString());
}
@Override
public Result invoke(Invocation inv) throws RpcException {
if (destroyed) {
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);
// 添加 attachments
if (attachment != null && attachment.size() > 0) {
invocation.addAttachmentsIfAbsent(attachment);
}
// 添加 context attachments
Map<String, String> 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;
}
type 属性,服务接口。url 属性,服务地址。attachment 属性,附加属性集合。available 属性,是否可用。destroyed 属性,是否销毁。#invoke(inv) 方法,调用服务的统一逻辑。
attachment 到 invocation 。context 到 invocation 。invocation 。RpcUtils#attachInvocationIdIfAsync(url, invocation) 方法,设置调用编号到 invocation 。#doInvoke(invocation) 抽象方法,执行调用。不同的协议,实现不同。com.alibaba.dubbo.rpc.Exporter ,暴露服务接口。代码如下:
Java复制public interface Exporter<T> {
/**
* get invoker.
*
* 获得 Invoker 对象
*
* @return invoker
*/
Invoker<T> getInvoker();
/**
* unexport.
*
* 取消暴露
*
* @throws java.lang.IllegalStateException
*/
void unexport();
}
#getInvoker() 方法,获得 Invoker 对象。#unexport() 方法,取消暴露。com.alibaba.dubbo.rpc.protocol.AbstractExporter ,实现 Exporter 接口,Exporter 抽象类。代码如下:
Java复制public abstract class AbstractExporter<T> implements Exporter<T> {
protected final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Invoker 对象
*/
private final Invoker<T> invoker;
/**
* 是否取消暴露服务
*/
private volatile boolean unexported = false;
public AbstractExporter(Invoker<T> invoker) {
if (invoker == null) {
throw new IllegalStateException("service invoker == null");
}
if (invoker.getInterface() == null) {
throw new IllegalStateException("service type == null");
}
if (invoker.getUrl() == null) {
throw new IllegalStateException("service url == null");
}
this.invoker = invoker;
}
@Override
public Invoker<T> getInvoker() {
return invoker;
}
@Override
public void unexport() {
if (unexported) {
return;
}
unexported = true;
getInvoker().destroy();
}
@Override
public String toString() {
return getInvoker().toString();
}
}
invoker 属性,Invoker 对象。unexported 属性,是否取消暴露服务。#unexport() 方法,取消暴露。若已经取消暴露,直接返回。否则,调用 Invoker#destroy() 方法,进行销毁。com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper ,实现 Protocol 接口,Protocol 过滤器包装实现类。代码如下:
Java复制public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
@Override
public int getDefaultPort() {
return protocol.getDefaultPort();
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
// 注册中心
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
// 建立带有 Filter 过滤链的 Invoker ,再暴露服务
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// 注册中心
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
// 引用服务,并建立带有 Filter 过滤链的 Invoker
return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}
@Override
public void destroy() {
protocol.destroy();
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
// 获得过滤器数组
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
// 倒序循环,创建带过滤链的 Invoker 对象
if (!filters.isEmpty()) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
@Override
public Class<T> getInterface() {
return invoker.getInterface();
}
@Override
public URL getUrl() {
return invoker.getUrl();
}
@Override
public boolean isAvailable() {
return invoker.isAvailable();
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
@Override
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
}
protocol 属性,协议对象。#export(invoker) 实现方法:
#buildInvokerChain(invoker, key, group) 方法,创建带 Filter 的 Invoker 对象。#refer(type, url) 实现方法:
#buildInvokerChain(invoker, key, group) 方法,创建带 Filter 的 Invoker 对象。#buildInvokerChain(invoker, key, group) 静态方法,创建带 Filter 链的 Invoker 对象。
ExtensionLoader#getActivateExtension(url, key, group) 方法,获得过滤器数组。last ,那么最终 last 就是首位的 Filter 。这一点,和 com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke(Invocation) 的正序循环不同。com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper ,实现 Protocol 接口,Protocol 监听器包装实现类。代码如下:
Java复制public class ProtocolListenerWrapper implements Protocol {
private final Protocol protocol;
public ProtocolListenerWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
@Override
public int getDefaultPort() {
return protocol.getDefaultPort();
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
// 注册中心协议
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
// 暴露服务,创建 ExporterListener 监听器
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// 注册中心协议
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
// 引用服务,创建 InvokerListener 监听器
return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(InvokerListener.class)
.getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
}
@Override
public void destroy() {
protocol.destroy();
}
}
protocol 属性,协议对象。#export(invoker) 实现方法:
#refer(type, url) 实现方法:
com.alibaba.dubbo.rpc.protocol.ListenerExporterWrapper ,实现 Exporter 接口,监听器 Exporter 包装器实现类。代码如下:
Java复制public class ListenerExporterWrapper<T> implements Exporter<T> {
/**
* 真实的 Exporter 对象
*/
private final Exporter<T> exporter;
/**
* Exporter 监听器数组
*/
private final List<ExporterListener> listeners;
public ListenerExporterWrapper(Exporter<T> exporter, List<ExporterListener> listeners) {
if (exporter == null) {
throw new IllegalArgumentException("exporter == null");
}
this.exporter = exporter;
this.listeners = listeners;
// 执行监听器
if (listeners != null && !listeners.isEmpty()) {
for (ExporterListener listener : listeners) {
if (listener != null) {
try {
listener.exported(this);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
}
}
@Override
public Invoker<T> getInvoker() {
return exporter.getInvoker();
}
@Override
public void unexport() {
try {
exporter.unexport();
} finally {
// 执行监听器
if (listeners != null && !listeners.isEmpty()) {
for (ExporterListener listener : listeners) {
if (listener != null) {
try {
listener.unexported(this);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
}
}
}
}
exporter 属性,真实的 Exporter 对象。listeners 属性,ExporterListener 监听器数组。listeners ,执行 ExporterListener#exported(exporter) 方法。#unexport() 方法,循环 listeners ,执行 ExporterListener#unexported(exporter) 方法。com.alibaba.dubbo.rpc.protocol.ListenerInvokerWrapper ,实现 Invoker 接口,监听器 Invoker 包装器实现类。代码如下:
Java复制public class ListenerInvokerWrapper<T> implements Invoker<T> {
private static final Logger logger = LoggerFactory.getLogger(ListenerInvokerWrapper.class);
/**
* 真实的 Invoker 对象
*/
private final Invoker<T> invoker;
/**
* Invoker 监听器数组
*/
private final List<InvokerListener> listeners;
public ListenerInvokerWrapper(Invoker<T> invoker, List<InvokerListener> listeners) {
if (invoker == null) {
throw new IllegalArgumentException("invoker == null");
}
this.invoker = invoker;
this.listeners = listeners;
// 执行监听器
if (listeners != null && !listeners.isEmpty()) {
for (InvokerListener listener : listeners) {
if (listener != null) {
try {
listener.referred(invoker);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
}
}
@Override
public Class<T> getInterface() {
return invoker.getInterface();
}
@Override
public URL getUrl() {
return invoker.getUrl();
}
@Override
public boolean isAvailable() {
return invoker.isAvailable();
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
@Override
public void destroy() {
try {
invoker.destroy();
} finally {
// 执行监听器
if (listeners != null && !listeners.isEmpty()) {
for (InvokerListener listener : listeners) {
if (listener != null) {
try {
listener.destroyed(invoker);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
}
}
}
@Override
public String toString() {
return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString());
}
}
invoker 属性,真实的 Invoker 对象。listeners 属性,InvokerListener 监听器数组。listeners ,执行 InvokerListener#referred(invoker) 方法。#destroy() 方法,循环 listeners ,执行 InvokerListener#destroyed(invoker) 方法。com.alibaba.dubbo.rpc.ExporterListener ,Exporter 监听器。代码如下:
Java复制@SPI
public interface ExporterListener {
/**
* The exporter exported.
*
* 当服务暴露完成
*
* @param exporter
* @throws RpcException
* @see com.alibaba.dubbo.rpc.Protocol#export(Invoker)
*/
void exported(Exporter<?> exporter) throws RpcException;
/**
* The exporter unexported.
*
* 当服务取消暴露完成
*
* @param exporter
* @throws RpcException
* @see com.alibaba.dubbo.rpc.Exporter#unexport()
*/
void unexported(Exporter<?> exporter);
}
com.alibaba.dubbo.rpc.listener.ExporterListenerAdapter ,实现 ExporterListener 接口,ExporterListener 适配器抽象类。代码如下:
Java复制public abstract class ExporterListenerAdapter implements ExporterListener {
public void exported(Exporter<?> exporter) throws RpcException {
}
public void unexported(Exporter<?> exporter) throws RpcException {
}
}
com.alibaba.dubbo.rpc.listener.DeprecatedExporterListener ,实现 ExporterListener 接口,记录日志在服务暴露完成时。代码如下:
Java复制@Activate(Constants.DEPRECATED_KEY)
public class DeprecatedExporterListener extends ExporterListenerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(DeprecatedExporterListener.class);
@Override
public void exported(Exporter<?> exporter) throws RpcException {
if (exporter.getUrl().getParameter(Constants.DEPRECATED_KEY, false)) {
LOGGER.error("The service " + exporter.getInvoker().getInterface().getName() + " is DEPRECATED! Declare from " + exporter.getInvoker().getUrl());
}
}
}
@Activate(Constants.DEPRECATED_KEY) 注解,基于 Dubbo SPI Activate 机制激活。其中,"deprecated" 配置项,可以设置服务是否已经废弃。com.alibaba.dubbo.rpc.InvokerListener ,Invoker 监听器。代码如下:
Java复制@SPI
public interface InvokerListener {
/**
* The invoker referred
*
* 当服务引用完成
*
* @param invoker
* @throws RpcException
* @see com.alibaba.dubbo.rpc.Protocol#refer(Class, URL)
*/
void referred(Invoker<?> invoker) throws RpcException;
/**
* The invoker destroyed.
*
* 当服务销毁引用完成
*
* @param invoker
* @throws RpcException
* @see com.alibaba.dubbo.rpc.Invoker#destroy()
*/
void destroyed(Invoker<?> invoker);
}
com.alibaba.dubbo.rpc.listener.InvokerListenerAdapter ,实现 InvokerListener 接口,InvokerListener 适配器抽象类。代码如下:
Java复制public abstract class InvokerListenerAdapter implements InvokerListener {
public void referred(Invoker<?> invoker) throws RpcException {
}
public void destroyed(Invoker<?> invoker) {
}
}
com.alibaba.dubbo.rpc.listener.DeprecatedInvokerListener ,实现 InvokerListener 接口,记录日志在服务引用完成时。代码如下:
Java复制@Activate(Constants.DEPRECATED_KEY)
public class DeprecatedInvokerListener extends InvokerListenerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(DeprecatedInvokerListener.class);
@Override
public void referred(Invoker<?> invoker) throws RpcException {
if (invoker.getUrl().getParameter(Constants.DEPRECATED_KEY, false)) {
LOGGER.error("The service " + invoker.getInterface().getName() + " is DEPRECATED! Declare from " + invoker.getUrl());
}
}
}
@Activate(Constants.DEPRECATED_KEY) 注解,基于 Dubbo SPI Activate 机制激活。其中,"deprecated" 配置项,可以设置服务是否已经废弃。com.alibaba.dubbo.rpc.Filter ,过滤器接口。代码如下:
Java复制@SPI
public interface Filter {
/**
* do invoke filter.
* <p>
* <code>
* // before filter
* Result result = invoker.invoke(invocation);
* // after filter
* return result;
* </code>
*
* @param invoker service
* @param invocation invocation.
* @return invoke result.
* @throws RpcException
* @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation)
*/
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
}
com.alibaba.dubbo.rpc.Invocation ,调用信息接口。代码如下:
Java复制public interface Invocation {
/**
* get method name.
*
* 获得方法名
*
* @return method name.
* @serial
*/
String getMethodName();
/**
* get parameter types.
*
* 获得参数类型数组
*
* @return parameter types.
* @serial
*/
Class<?>[] getParameterTypes();
/**
* get arguments.
*
* 获得参数值数组
*
* @return arguments.
* @serial
*/
Object[] getArguments();
/**
* get attachments.
*
* 获得附加信息集合
*
* @return attachments.
* @serial
*/
Map<String, String> getAttachments();
/**
* get attachment by key.
*
* 获得指定键的附加信息
*
* @return attachment value.
* @serial
*/
String getAttachment(String key);
/**
* get attachment by key with default value.
*
* 获得指定键的附加信息,不存在则返回默认值
*
* @return attachment value.
* @serial
*/
String getAttachment(String key, String defaultValue);
/**
* get the invoker in current context.
*
* 获得 Invoker 对象
*
* @return invoker.
* @transient
*/
Invoker<?> getInvoker();
}
Invoker#invoke(invocation) 方法的参数。com.alibaba.dubbo.rpc.RpcInvocation ,实现 Invocation 接口,RPC 调用信息实现类。代码如下:
Java复制public class RpcInvocation implements Invocation, Serializable {
private static final long serialVersionUID = -4355285085441097045L;
/**
* 方法名
*/
private String methodName;
/**
* 参数类型数组
*/
private Class<?>[] parameterTypes;
/**
* 参数值数组
*/
private Object[] arguments;
/**
* 附加信息集合
*/
private Map<String, String> attachments;
/**
* 隐式传参集合
*
* 例如,http://dubbo.apache.org/zh-cn/docs/user/demos/attachment.html
*/
private transient Map<Object, Object> attributes;
/**
* Invoker 对象
*/
private transient Invoker<?> invoker;
public RpcInvocation() {
}
public RpcInvocation(Invocation invocation, Invoker<?> invoker) {
this(invocation.getMethodName(), invocation.getParameterTypes(),
invocation.getArguments(), invocation.getAttachments(), invocation.getInvoker());
if (invoker != null) {
URL url = invoker.getUrl();
// 设置异步信息到 `attachments` 集合
setAttachment(Constants.ASYNC_KEY, Boolean.toString(url.getMethodParameter(getMethodName(), Constants.ASYNC_KEY, false)));
// 设置调用编号到 `attachments` 集合
setAttachment(Constants.ATTACHMENT_KEY, url.getMethodParameter(getMethodName(), Constants.ATTACHMENT_KEY));
}
this.invoker = invoker;
}
public RpcInvocation(Invocation invocation) {
this(invocation.getMethodName(), invocation.getParameterTypes(),
invocation.getArguments(), invocation.getAttachments(), invocation.getInvoker());
}
public RpcInvocation(Method method, Object[] arguments) {
this(method.getName(), method.getParameterTypes(), arguments, null, null);
}
public RpcInvocation(Method method, Object[] arguments, Map<String, String> attachment) {
this(method.getName(), method.getParameterTypes(), arguments, attachment, null);
}
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments