如何实现服的消费
- 生成远程服务的代理
- 获取目标服务的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