如何实现服的消费
- 生成远程服务的代理
- 获取目标服务的url地址
- 实现远程网络通信
- 实现负载均衡
- 实现集群容错

Invoker

服务引入
消费端的代码解析是从下面这段代码开始的
<dubbo:reference id="xxxService" interface="xxx.xxx.Service"/>
注解的方式的初始化入口是
ReferenceAnnotationBeanPostProcessor
->ReferenceBeanInvocationHandler.init
->ReferenceConfig.get() 获得一个远程代理类
ReferenceBean
服务引用的入口方法为 ReferenceBean 的 getObject 方法,该方法定义在 Spring 的 FactoryBean 接口中
/**
* ReferenceFactoryBean
*/
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
ApplicationContextAware, InitializingBean, DisposableBean {
private static final long serialVersionUID = 213195494150089726L;
private transient ApplicationContext applicationContext;
public ReferenceBean() {
super();
}
public ReferenceBean(Reference reference) {
super(reference);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
@Override
// 这是入口方法
public Object getObject() {
return get();
}
@Override
public Class<?> getObjectType() {
return getInterfaceClass();
}
@Override
@Parameter(excluded = true)
public boolean isSingleton() {
return true;
}
/**
* Initializes there Dubbo's Config Beans before @Reference bean autowiring
*/
private void prepareDubboConfigBeans() {
beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class);
beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class);
beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class);
beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class);
beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class);
beansOfTypeIncludingAncestors(applicationContext, SslConfig.class);
}
@Override
@SuppressWarnings({"unchecked"})
public void afterPropertiesSet() throws Exception {
// 加载 dubbo的ConfigBean到ioc容器中
prepareDubboConfigBeans();
// 默认懒加载 可以通过@Reference(init = true)
if (init == null) {
init = false;
}
// eager init if necessary.
if (shouldInit()) {
getObject();
}
}
@Override
public void destroy() {
// do nothing
}
}
ReferenceConfig.get
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
// 如果当前接口的远程代理引用为空,则进行初始化
if (ref == null) {
init();
}
return ref;
}
ReferenceConfig.init
public synchronized void init() {
// 避免重复初始化
if (initialized) {
return;
}
if (bootstrap == null) {
bootstrap = DubboBootstrap.getInstance();
bootstrap.init();
}
// 检查和修改配置
checkAndUpdateSubConfigs();
//init serivceMetadata 初始化 服务元数据
serviceMetadata.setVersion(version);
serviceMetadata.setGroup(group);
serviceMetadata.setDefaultGroup(group);
serviceMetadata.setServiceType(getActualInterface());
serviceMetadata.setServiceInterfaceName(interfaceName);
// TODO, uncomment this line once service key is unified
serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
// 检查本地服务
checkStubAndLocal(interfaceClass);
ConfigValidationUtils.checkMock(interfaceClass, this);
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, CONSUMER_SIDE);
ReferenceConfigBase.appendRuntimeParameters(map);
if (!ProtocolUtils.isGeneric(generic)) {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("No method found in service interface " + interfaceClass.getName());
map.put(METHODS_KEY, ANY_VALUE);
} else {
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));
}
}
map.put(INTERFACE_KEY, interfaceName);
AbstractConfig.appendParameters(map, getMetrics());
AbstractConfig.appendParameters(map, getApplication());
AbstractConfig.appendParameters(map, getModule());
// remove 'default.' prefix for configs from ConsumerConfig
// appendParameters(map, consumer, Constants.DEFAULT_KEY);
AbstractConfig.appendParameters(map, consumer);
AbstractConfig.appendParameters(map, this);
Map<String, Object> attributes = null;
if (CollectionUtils.isNotEmpty(getMethods())) {
attributes = new HashMap<>();
for (MethodConfig methodConfig : getMethods()) {
AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName());
String retryKey = methodConfig.getName() + ".retry";
if (map.containsKey(retryKey)) {
String retryValue = map.remove(retryKey);
if ("false".equals(retryValue)) {
map.put(methodConfig.getName() + ".retries", "0");
}
}
ConsumerModel.AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig);
if (asyncMethodInfo != null) {
// consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo);
attributes.put(methodConfig.getName(), asyncMethodInfo);
}
}
}
// 获取服务消费者 ip 地址
String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
if (StringUtils.isEmpty(hostToRegistry)) {
hostToRegistry = NetUtils.getLocalHost();
} else if (isInvalidLocalHost(hostToRegistry)) {
throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
}
map.put(REGISTER_IP_KEY, hostToRegistry);
serviceMetadata.getAttachments().putAll(map);
/******************上面都是参数组装********************/
// 元数据中心注册
ServiceRepository repository = ApplicationModel.getServiceRepository();
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
repository.registerConsumer(
serviceMetadata.getServiceKey(),
attributes,
serviceDescriptor,
this,
null,
serviceMetadata);
// 创建代理类引用 这个才是关键
ref = createProxy(map);
serviceMetadata.setTarget(ref);
serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);
repository.lookupReferredService(serviceMetadata.getServiceKey()).setProxyObject(ref);
initialized = true; // 设置已经初始化
// dispatch a ReferenceConfigInitializedEvent since 2.7.4
dispatch(new ReferenceConfigInitializedEvent(this, invoker));
}
ReferenceConfig.createProxy
- 判断是否为本地调用,如果是则使用injvm协议进行调用
- 判断是否为点对点调用,如果是则把url保存到urls集合中,如果url为1,进入步骤4,如果urls>1,则执行5 3. 如果是配置了注册中心,遍历注册中心,把url添加到urls集合,url为1,进入步骤4,如果urls>1,则执行5
- 直连构建invoker
- 构建invokers集合,通过cluster合并多个invoker
- 最后调用 ProxyFactory 生成代理类
private T createProxy(Map<String, String> map) {
// 判断是否是在同一个jvm进程中调用
if (shouldJvmRefer(map)) {
URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
invoker = REF_PROTOCOL.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
} else {
urls.clear();
// @Reference(url = "http://xxx") 直连方式
// url如果不为空,说明是点对点通信
if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
if (us != null && us.length > 0) {
for (String u : us) {
URL url = URL.valueOf(u);
if (StringUtils.isEmpty(url.getPath())) {
url = url.setPath(interfaceName);
}
// 检测url协议是否为registry,若是,表明用户想使用的指定的注册中心
if (UrlUtils.isRegistry(url)) {
// 将map转换为查询字符串,并作为refer参数的值添加到url中
urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
} else {
// 合并url,移除服务提供者的一些配置(这些配置来源用户配置的url属性)
// 比如线程池相关配置。并保留服务提供者的部分配置,比如版本,group,时间戳等
// 最后合将合并的配置设置url查询字符串中
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
} else { // assemble URL from register center's configuration
// if protocols not injvm checkRegistry
if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
// 检验注册中心的配置以及是否必要从配置中心组装url
checkRegistry();
// 这里的代码实现和服务端类似,也是根据注册中心配置解析等到的url
// 这里的url:registry://192.168.0.4:2181/org.apache.dubbo.registry.RegistryService
List<URL> us = ConfigValidationUtils.loadRegistries(this, false);
if (CollectionUtils.isNotEmpty(us)) {
for (URL u : us) {
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);
if (monitorUrl != null) {
map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
}
}
// 如果没有配置注册中心,则报错
if (urls.isEmpty()) {
throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
}
}
}
// 如果配置了一个注册中心或者一个服务提供者,直接使用refprotocol.refer
if (urls.size() == 1) {
// Protocol$Adaptive --> RegistryProtocol.refer
invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
} else { // 配置多个注册中心
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
URL registryURL = null;
for (URL url : urls) { // 遍历urls生成多个invoker
invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
if (UrlUtils.isRegistry(url)) {
registryURL = url; // use last registry url
}
}
if (registryURL != null) { // 如果registryURL不为空,构建静态directory
// 使用ZoneAwareCluster
URL u = registryURL.addParameterIfAbsent(CLUSTER_KEY, ZoneAwareCluster.NAME);
// 通过Cluster将多个invoker合并ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here)-> Invoker
invoker = CLUSTER.join(new StaticDirectory(u, invokers));
} else { // not a registry url, must be direct invoke.
invoker = CLUSTER.join(new StaticDirectory(invokers));
}
}
}
// 检查invoker的有效性
if (shouldCheck() && !invoker.isAvailable()) {
throw new IllegalStateException("Failed to check the status of the service "
+ interfaceName
+ ". No provider available for the service "
+ (group == null ? "" : group + "/")
+ interfaceName +
(version == null ? "" : ":" + version)
+ " from the url "
+ invoker.getUrl()
+ " to the consumer "
+ NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
}
/**
* @since 2.7.0
* ServiceData Store
*/
String metadata = map.get(METADATA_KEY);
WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? DEFAULT_METADATA_STORAGE_TYPE : metadata);
if (metadataService != null) {
URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
metadataService.publishServiceDefinition(consumerURL);
}
// create service proxy 创建服务代理类
return (T) PROXY_FACTORY.getProxy(invoker);
}
protocol.refer
通过指定的协议来调用refer生成一个invoker对象,invoker前面讲过,它是一个代理对象。那么在当前的消费端而言,invoker主要用于执行远程调用。这个protocol,又是一个自适应扩展点,它得到的是一个Protocol$Adaptive.
private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
根据当前的协议url,得到一个指定的扩展点,传递进来的参数中,协议地址为registry://,所以,我们可以直接定位到RegistryProtocol.refer代码
Protocol$Adaptive中的refer方法
public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
根据当前的协议扩展名registry, 获得一个被包装过的RegistryProtocol
RegistryProtocol.refer
- (1) 组装注册中心协议url
- (2) 判断是否配置legroup,如果有,则cluster=getMergeableCluster(),构建invoker
- (3) doRefer构建invoker
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// (1) 组装注册中心协议rul
// url: zookeeper://192.168.0.4:2181/org.apache.dubbo.registry.RegistryService?xxx
url = getRegistryUrl(url);
// registryFactory-> RegistryFactory$Aaptive -> zookeeperRegistryFactory.getRegistry
// registry 最终返回 zookeeperRegistry 使用curator建立到zookeeper的连接
Registry registry = registryFactory.getRegistry(url);
if (RegistryService.class.equals(type)) {
return proxyFactory.getInvoker((T) registry, type, url);
}
// group="a,b" or group="*"
// 解析group参数,根据group决定cluster的类型
Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
String group = qs.get(GROUP_KEY);
if (group != null && group.length() > 0) {
if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
// 通过SPI加载MergeableCluster实例,并调用doRefer继续执行
return doRefer(getMergeableCluster(), registry, type, url);
}
}
// 构建invoker 调用doRefer继续执行服务引用逻辑
return doRefer(cluster, registry, type, url);
}
// 根据配置的协议组装url
protected URL getRegistryUrl(URL url) {
return URLBuilder.from(url)
.setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY))
.removeParameter(REGISTRY_KEY)
.build();
}
RegistryProtocol.doRefer
- 构建一个RegistryDirectory
- 构建一个consumer://协议的地址注册到注册中心
- 订阅zookeeper中节点的变化
- 调用cluster.join方法
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
// RegistryDirectory初始化
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
// 设置注册中心和协议
directory.setRegistry(registry);
directory.setProtocol(protocol);
// all attributes of REFER_KEY
Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
// url:consumer://192.168.0.4/com.test.dubbo.DemoService?xxx
URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
// 注册服务消费者,在consumers 目前下新节点
if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {
directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url));
// 注册consumer://协议的url
registry.register(directory.getRegisteredConsumerUrl());
}
// 构建routerChain
directory.buildRouterChain(subscribeUrl);
// 订阅 providers,configurators,routers等节点数据
directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));
// 一个注册中心可能有多个服务提供者,因此这里需要将多个服务提供者合并为一个 后面负责均衡用到
// 这里返回的invoker,应该是MockClusterWrapper(FailOverCluster(directory))
Invoker invoker = cluster.join(directory);
return invoker;
}
doRefer 方法创建一个 RegistryDirectory 实例,然后生成服务者消费者链接,并向注册中心进行注册。注册完毕后,紧接着订阅 providers、configurators、routers 等节点下的数据。完成订阅后,RegistryDirectory 会收到这几个节点下的子节点信息。由于一个服务可能部署在多台服务器上,这样就会在 providers 产生多个节点,这个时候就需要 Cluster 将多个服务节点合并为一个,并生成一个 Invoker。关于 RegistryDirectory 和 Cluster,这里不再分析,后面单独分析。
proxyFactory.getProxy创建代理
ReferenceConfig.createProxy方法中的最后一行,拿到invoker之后,会调用获得一个动态代理类
return (T) PROXY_FACTORY.getProxy(invoker);
proxyFactory是一个SPI扩展点 可以直接看StubProxyFactoryWrapper(JavassistProxyFactory)
JavassistProxyFactory中没有getProxy(xx)一个参数的方法会调用其父类的方法AbstractProxyFactory#getProxy(Invoker<T>)
可以直接从AbstractProxyFactory.getProxy分析
AbstractProxyFactory.getProxy
public abstract class AbstractProxyFactory implements ProxyFactory {
private static final Class<?>[] INTERNAL_INTERFACES = new Class<?>[]{
EchoService.class, Destroyable.class
};
@Override
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
// 调用重载方法
return getProxy(invoker, false);
}
@Override
public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {
Set<Class<?>> interfaces = new HashSet<>();
// 获取接口配置
String config = invoker.getUrl().getParameter(INTERFACES);
if (config != null && config.length() > 0) {
// 切分接口列表
String[] types = COMMA_SPLIT_PATTERN.split(config);
if (types != null && types.length > 0) {
for (int i = 0; i < types.length; i++) {
// TODO can we load successfully for a different classloader?.
interfaces.add(ReflectUtils.forName(types[i]));
}
}
}
if (!GenericService.class.isAssignableFrom(invoker.getInterface()) && generic) {
interfaces.add(com.alibaba.dubbo.rpc.service.GenericService.class);
}
// 添加接口
interfaces.add(invoker.getInterface());
// 添加服务类接口 EchoService.class, Destroyable.class
interfaces.addAll(Arrays.asList(INTERNAL_INTERFACES));
// 调用模板重载方法
return getProxy(invoker, interfaces.toArray(new Class<?>[0]));
}
// 模板方法 由子类实现 如:JavassistProxyFactory.getProxy
public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);
}
JavassistProxyFactory.getProxy
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
// 生成 Proxy 子类(Proxy 是抽象类)。并调用 Proxy 子类的 newInstance 方法创建 Proxy 实例
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
通过 Proxy 的 getProxy 方法获取 Proxy 子类,然后创建 InvokerInvocationHandler 对象,并将该对象传给 newInstance 生成 Proxy 实例
InvokerInvocationHandler 实现 JDK 的 InvocationHandler 接口,具体的用途是拦截接口类调用
Proxy.getProxy
public static Proxy getProxy(Class<?>... ics) {
// 调用重载方法
return getProxy(ClassUtils.getClassLoader(Proxy.class), ics);
}
public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
if (ics.length > MAX_PROXY_COUNT) {
throw new IllegalArgumentException("interface limit exceeded");
}
StringBuilder sb = new StringBuilder();
// 遍历接口列表
for (int i = 0; i < ics.length; i++) {
String itf = ics[i].getName();
// 检查类型是否为接口
if (!ics[i].isInterface()) {
throw new RuntimeException(itf + " is not a interface.");
}
Class<?> tmp = null;
try {
// 重新加载接口类
tmp = Class.forName(itf, false, cl);
} catch (ClassNotFoundException e) {
}
// 检测接口是否相同,这里tmp有可能为空
if (tmp != ics[i]) {
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
}
// 拼接接口全限定名,分割符为
sb.append(itf).append(';');
}
// 使用拼接后的接口名作为key
//eg: com.alibaba.dubbo.rpc.service.EchoService;com.test.dubbo.DemoService;org.apache.dubbo.rpc.service.Destroyable;
String key = sb.toString();
// get cache by class loader.
final Map<String, Object> cache;
synchronized (PROXY_CACHE_MAP) {
cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new HashMap<>());
}
Proxy proxy = null;
synchronized (cache) {
do {
// 从缓存中获取Reference<Proxy>实例
Object value = cache.get(key);
if (value instanceof Reference<?>) {
proxy = (Proxy) ((Reference<?>) value).get();
if (proxy != null) {
return proxy;
}
}
// 并发控制,保证只有一个线程可以进行后续操作
if (value == PENDING_GENERATION_MARKER) {
try {
// 其他线程在此处进行等待
cache.wait();
} catch (InterruptedException e) {
}
} else {
// 放置标志为到缓存,并跳出while循环进行后续操作
cache.put(key, PENDING_GENERATION_MARKER);
break;
}
}
while (true);
}
long id = PROXY_CLASS_COUNTER.getAndIncrement();
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try {
// 创建ClassGenerator对象
ccp = ClassGenerator.newInstance(cl);
Set<String> worked = new HashSet<>();
List<Method> methods = new ArrayList<>();
for (int i = 0; i < ics.length; i++) {
// 检测接口访问级别是否为protocted或private
if (!Modifier.isPublic(ics[i].getModifiers())) {
// 获取接口报名
String npkg = ics[i].getPackage().getName();
if (pkg == null) {
pkg = npkg;
} else {
// 非public级别的接口必须在同一个包下,否则抛出异常
if (!pkg.equals(npkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
// 添加接口到ClassGenerator中
ccp.addInterface(ics[i]);
// 遍历接口方法
for (Method method : ics[i].getMethods()) {
// 获取方法描述,可以理解为方法签名
String desc = ReflectUtils.getDesc(method);
// 如果方法描述字符串已在 worked 中,则忽略。考虑这种情况,
// A 接口和 B 接口中包含一个完全相同的方法
if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {
continue;
}
if (ics[i].isInterface() && Modifier.isStatic(method.getModifiers())) {
continue;
}
worked.add(desc);
int ix = methods.size();
// 获取方法返回值类型
Class<?> rt = method.getReturnType();
Class<?>[] pts = method.getParameterTypes();
// 生成 Object[] args = new Object[1...N]
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for (int j = 0; j < pts.length; j++) {
// 生成 args[1...N] = ($w)$1...N;
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
}
code.append(" Object ret = handler.invoke(this, methods[").append(ix).append("], args);");
// 返回值不为 void
if (!Void.TYPE.equals(rt)) {
// 生成返回语句,形如 return (java.lang.String) ret;
code.append(" return ").append(asArgument(rt, "ret")).append(";");
}
methods.add(method);
// 添加方法名、访问控制符、参数列表、方法代码等信息到 ClassGenerator 中
ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
}
}
if (pkg == null) {
pkg = PACKAGE_NAME;
}
// 构建接口代理类名称:pkg + ".proxy" + id,比如 org.apache.dubbo.proxy0
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
// 生成 private java.lang.reflect.InvocationHandler handler
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
// 为接口代理类添加默认构造方法
ccp.addDefaultConstructor();
// 生成接口代理类
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// 构建 Proxy 子类名称,比如 Proxy1,Proxy2 等
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
// 生成 Proxy 实现类
Class<?> pc = ccm.toClass();
// 通过反射创建 Proxy 实例
proxy = (Proxy) pc.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
// 释放资源
if (ccp != null) {
ccp.release();
}
if (ccm != null) {
ccm.release();
}
synchronized (cache) {
if (proxy == null) {
cache.remove(key);
} else {
// 写缓存
cache.put(key, new WeakReference<Proxy>(proxy));
}
// 唤醒其他等待线程
cache.notifyAll();
}
}
return proxy;
}

最终会生成如proxy0类
package org.apache.dubbo.common.bytecode;
public class proxy0 implements com.test.dubbo.DemoService, EchoService, DemoService {
public static java.lang.reflect.Method[] methods;
private java.lang.reflect.InvocationHandler handler;
public proxy0() {
}
public proxy0(java.lang.reflect.InvocationHandler arg0) {
handler = $1;
}
public java.lang.String sayHello(java.lang.String arg0) {
// 将参数存储到 Object 数组中
Object[] args = new Object[1];
args[0] = ($w) $1;
// 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
Object ret = handler.invoke(this, methods[0], args);
// 返回调用结果
return (java.lang.String) ret;
}
/** 回声测试方法 */
public Object $echo(Object object) {
Object[] arrobject = new Object[]{object};
Object object2 = this.handler.invoke(this, methods[1], arrobject);
return object2;
}
}
从这个sayHello方法可以看出,我们通过@Reference注入的一个对象实例本质上就是一个动态代理类,通过调用这个类中的方法,会触发
handler.invoke(), 而这个handler就是InvokerInvocationHandler
服务调用
proxy0#sayHello(String)
—> InvokerInvocationHandler#invoke(Object, Method, Object[])
—> MockClusterInvoker#invoke(Invocation)
—> AbstractClusterInvoker#invoke(Invocation)
—> FailoverClusterInvoker#doInvoke(Invocation, List<Invoker<T>>, LoadBalance)
—> Filter#invoke(Invoker, Invocation) // 包含多个 Filter 调用
—> ListenerInvokerWrapper#invoke(Invocation)
—> AbstractInvoker#invoke(Invocation)
—> DubboInvoker#doInvoke(Invocation)
—> ReferenceCountExchangeClient#request(Object, int)
—> HeaderExchangeClient#request(Object, int)
—> HeaderExchangeChannel#request(Object, int)
—> AbstractPeer#send(Object)
—> AbstractClient#send(Object, boolean)
—> NettyChannel#send(Object, boolean)
—> NioClientSocketChannel#write(Object)
消费者服务调用 invoker的链条调用 回顾上面的Proxy0$sayHello()调用 handler.invoke
public java.lang.String sayHello(java.lang.String arg0) {
// 将参数存储到 Object 数组中
Object[] args = new Object[1];
args[0] = ($w) $1;
// 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
Object ret = handler.invoke(this, methods[0], args);
// 返回调用结果
return (java.lang.String) ret;
}
proxy0.handler是在JavassistProxyFactory.getProxy获取代理类时构造的,入口InvokerInvocationHandler
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
InvokerInvocationHandler
public class InvokerInvocationHandler implements InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(InvokerInvocationHandler.class);
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
// 获取服务方法名
String methodName = method.getName();
// 获取方法的参数
Class<?>[] parameterTypes = method.getParameterTypes();
// 非服务类的方法 直接调用
if (parameterTypes.length == 0) {
if ("toString".equals(methodName)) {
return invoker.toString();
} else if ("$destroy".equals(methodName)) {
invoker.destroy();
return null;
} else if ("hashCode".equals(methodName)) {
return invoker.hashCode();
}
} else if (parameterTypes.length == 1 && "equals".equals(methodName)) {
return invoker.equals(args[0]);
}
// 将method和args封装到RpcInvocation中,传输对象,并执行后续的调用
RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), args);
rpcInvocation.setTargetServiceUniqueName(invoker.getUrl().getServiceKey());
// 这个invoker是MockClusterInvoker 是通过Cluster的扩展点的包装类MockClusterWrapper构建的
return invoker.invoke(rpcInvocation).recreate();
}
}
MockClusterInvoker.invoke
Mock,在这里面有两个逻辑
- 是否客户端强制配置了mock调用,那么在这种场景中主要可以用来解决服务端还没开发好的时候
直接使用本地数据进行测试 - 是否出现了异常,如果出现异常则使用配置好的Mock类来实现服务的降级
public class MockClusterInvoker<T> implements Invoker<T> {
private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class);
private final Directory<T> directory;
private final Invoker<T> invoker;
public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
this.directory = directory;
this.invoker = invoker;
}
@Override
public URL getUrl() {
return directory.getUrl();
}
@Override
public boolean isAvailable() {
return directory.isAvailable();
}
@Override
public void destroy() {
this.invoker.destroy();
}
@Override
public Class<T> getInterface() {
return directory.getInterface();
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// 获取mock配置
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || "false".equalsIgnoreCase(value)) {
//no mock
// 无mock逻辑,直接调用其他Invoker对象的inoker方法
// 比如: FailOverCluster 可以通过:@Reference(cluster="failover")配置
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
}
//force:direct mock
// force:xx 直接执行mock逻辑,不乏其远程调用
result = doMockInvoke(invocation, null);
} else {
//fail-mock
// fail:xxx 表示消费方调用服务失败后,再执行mock逻辑,不抛出异常
try {
// 调用其他的Invoker对象的invoke方法
result = this.invoker.invoke(invocation);
//fix:#4585 返回有异常情况
if(result.getException() != null && result.getException() instanceof RpcException){
RpcException rpcException= (RpcException)result.getException();
if(rpcException.isBiz()){ // 业务异常直接返回
throw rpcException;
}else {
// 非业务异常 服务降级mock逻辑
result = doMockInvoke(invocation, rpcException);
}
}
} catch (RpcException e) {
if (e.isBiz()) { // 业务异常直接返回
throw e;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
}
// 非业务异常 调用降级mock逻辑
result = doMockInvoke(invocation, e);
}
}
return result;
}
// 省略其他方法
}
AbstractClusterInvoker.invoke
下一个invoke,应该是FailoverClusterInvoker,它本身没有invoke方法,直接进入其父类AbstractClusterInvoker的invoker方法,有回调它的模板方法doInvoke
public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
// 保存从注册中心的拉取的所有invoker 目录
protected Directory<T> directory;
protected boolean availablecheck; // 可用性检查
private AtomicBoolean destroyed = new AtomicBoolean(false);
// 粘性invoker 是否支持粘性调用
private volatile Invoker<T> stickyInvoker = null;
@Override
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
// binding attachments into invocation.
// 隐式参数
// 绑定attachments,Dubbo中,可以通过 RpcContext 上的 setAttachment 和 getAttachment
// 在服务消费方和提供方之间进行参数的隐式传递,所以这段代码中会去绑定attachments
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation) invocation).addAttachments(contextAttachments);
}
// 通过list获取invoker列表,这个列表是从directory里面获得的
List<Invoker<T>> invokers = list(invocation);
// 加载loadBalance
LoadBalance loadbalance = initLoadBalance(invokers, invocation);
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
return doInvoke(invocation, invokers, loadbalance);
}
protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
// 调用Directory的list方法列举Invoker
return directory.list(invocation);
}
// 初始化负载均衡策略
protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
// 通过SPI获取LoadBalance 默认 random
if (CollectionUtils.isNotEmpty(invokers)) {
return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
.getMethodParameter(RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE));
} else {
return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);
}
}
}
FailoverClusterInvoker.doInvoke
容错机制
容错的逻辑:failover失败重试
- 获得重试的次数,并且进行循环
- 获得目标服务,并且记录当前已经调用过的目标服务防止下次继续将请求发送过去
- 如果执行成功,则返回结果
- 如果出现异常,判断是否为业务异常,如果是则抛出,否则,进行下一次重试
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
List<Invoker<T>> copyInvokers = invokers;
checkInvokers(copyInvokers, invocation);
String methodName = RpcUtils.getMethodName(invocation);
// 获取重试次数 默认2次
int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
if (len <= 0) {
len = 1;
}
// retry loop.
RpcException le = null; // last exception.
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
Set<String> providers = new HashSet<String>(len);
// 循环调用,失败重试
for (int i = 0; i < len; i++) {
if (i > 0) {
checkWhetherDestroyed();
// 在进行重试前重新列举 Invoker,这样做的好处是,如果某个服务挂了,
// 通过调用 list 可得到最新可用的 Invoker 列表
copyInvokers = list(invocation);
// 对 copyinvokers 进行判空检查
checkInvokers(copyInvokers, invocation);
}
// 通过负载均衡选择invoker
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
// 记录已经调用过的服务,下次调用会进行过滤
invoked.add(invoker);
// 设置 invoked 到 RPC 上下文中
RpcContext.getContext().setInvokers((List) invoked);
try {
// 服务调用成功,直接返回
Result result = invoker.invoke(invocation);
if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + methodName
+ " in the service " + getInterface().getName()
+ " was successful by the provider " + invoker.getUrl().getAddress()
+ ", but there have been failed providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Last error is: "
+ le.getMessage(), le);
}
return result;
} catch (RpcException e) {
if (e.isBiz()) { // 如果是业务异常,直接抛出不进行重试
throw e;
}
le = e; // 记录异常信息,进行下一次循环
} catch (Throwable e) {
le = new RpcException(e.getMessage(), e);
} finally {
providers.add(invoker.getUrl().getAddress());
}
}
// 若重试失败,则抛出异常
throw new RpcException(le.getCode(), "Failed to invoke the method "
+ methodName + " in the service " + getInterface().getName()
+ ". Tried " + len + " times of the providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ Version.getVersion() + ". Last error is: "
+ le.getMessage(), le.getCause() != null ? le.getCause() : le);
}
toInvokers
RegistryDirectory
在RegistryDirectory中有一个成员属性,保存了服务地方地址对应的invoke信息
private volatile Map<String, Invoker<T>> urlInvokerMap;
toInvokers
这个invoker是动态的,基于注册中心的变化而变化的。它的初始化过程的链路是
RegistryDirectory.notify->refreshInvoker->toInvokers
if (enabled) {
invoker = new InvokerDelegate<>(protocol.refer(serviceType, url), url, providerUrl);
}
基于protocol.refer来构建的invoker,并且使用InvokerDelegate进行了委托,在DubboProtocol中,
是这样构建invoker的。返回的是一个DubboInvoker对象
// AbstractProtocol#refer
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
return new AsyncToSyncInvoker<>(protocolBindingRefer(type, url));
}
// DubboProtocol#protocolBindingRefer
public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
optimizeSerialization(url);
// create rpc invoker.
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
invokers.add(invoker);
return invoker;
}
综合上述通过url转成的invoker是
InvokerDelegate
->QosProtocolWrapper->ProtocolListenerWrapper->ProtocolFilterWrapper
->AbstractProtocol->DubboProtocol
->AsyncToSyncInvoker // 异步到同步invoke
->DubboInvoker
DubboInvoker
AbstractInvoker#invoke
// 对Invocation的attachments进行处理,把attachment加入到Invocation中
public Result invoke(Invocation inv) throws RpcException {
// if invoker is destroyed due to address refresh from registry, let's allow the current invoke to proceed
if (destroyed.get()) {
logger.warn("Invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + " is destroyed, "
+ ", dubbo version is " + Version.getVersion() + ", this invoker should not be used any longer");
}
RpcInvocation invocation = (RpcInvocation) inv;
// 设置invoker
invocation.setInvoker(this);
if (CollectionUtils.isNotEmptyMap(attachment)) {
// 设置attachment
invocation.addAttachmentsIfAbsent(attachment);
}
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
// 添加 contextAttachments 到 RpcInvocation#attachment 变量中
invocation.addAttachments(contextAttachments);
}
// 设置调用模式 同步/异步调用
invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
// 设置异步调用Id
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
AsyncRpcResult asyncResult;
try {
// 抽象方法,有子类实现
asyncResult = (AsyncRpcResult) doInvoke(invocation);
} catch (InvocationTargetException e) { // biz exception
Throwable te = e.getTargetException();
if (te == null) {
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
}
} catch (RpcException e) {
if (e.isBiz()) {
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
throw e;
}
} catch (Throwable e) {
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
}
// 封装CompletableFuture 异步调用返回
RpcContext.getContext().setFuture(new FutureAdapter(asyncResult.getResponseFuture()));
return asyncResult;
}
protected abstract Result doInvoke(Invocation invocation) throws Throwable;
DubboInvoker.doInvoke
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
// 获取调用方法名
final String methodName = RpcUtils.getMethodName(invocation);
// 设置path和version到attachment中
inv.setAttachment(PATH_KEY, getUrl().getPath());
inv.setAttachment(VERSION_KEY, version);
ExchangeClient currentClient;
// 从clients数组中获取ExchangeClient
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
// 获取异步配置
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
// 获取超时数据 默认是 1s
int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);
// oneWay 为true 表示“单向"通信 没有返回值 kafka的消费发送方式 也有 oneWay
if (isOneway) {
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent); // 发送请求
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else { // 有返回值处理
ExecutorService executor = getCallbackExecutor(getUrl(), inv);
CompletableFuture<AppResponse> appResponseFuture =
currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(appResponseFuture);
AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
result.setExecutor(executor);
return result;
}
} catch (TimeoutException e) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (RemotingException e) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
protected ExecutorService getCallbackExecutor(URL url, Invocation inv) {
ExecutorService sharedExecutor = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().getExecutor(url);
if (InvokeMode.SYNC == RpcUtils.getInvokeMode(getUrl(), inv)) {
return new ThreadlessExecutor(sharedExecutor);
} else {
return sharedExecutor;
}
}
ExchangeClient
ReferenceCountExchangeClient(HeaderExchangeClient())
调用链路
ReferenceCountExchangeClient->HeaderExchangeClient->HeaderExchangeChannel->(request())
把构建好的RpcInvocation,组装到一个Request对象中进行传递
HeaderExchangeChannel#request()
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
if (closed) {
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
// 创建请求对象
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
req.setData(request);
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
try {
channel.send(req); // NettyClient
} catch (RemotingException e) {
future.cancel();
throw e;
}
return future;
}
channel.send(req)调用链路
AbstractPeer.send ->AbstractClient.send->NettyChannel.send
最终 通过NioSocketChannel把消息发送出去
ChannelFuture future = channel.writeAndFlush(msg);
本文详细介绍了Dubbo服务消费的过程,包括服务引入、创建代理、服务调用的内部实现,如ReferenceBean、InvokerInvocationHandler、协议引用等。内容涵盖了从初始化入口ReferenceBean开始,经由protocol.refer创建invoker,通过ProxyFactory生成代理类,到最后的服务调用和容错处理,揭示了Dubbo在消费端的完整工作流程。
1500

被折叠的 条评论
为什么被折叠?



