一 入口
public static void main(String[] args) {
// 引用远程服务 此实例很重 封装了与注册中心的连接以及与提供者的连接
ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();
reference.setApplication(new ApplicationConfig("native-consumer")); // 配置应用信息
reference.setRegistry(new RegistryConfig("zookeeper://localhost:2181")); // 配置注册中心信息
reference.setInterface(DemoService.class); // 引用的远程服务的接口抽象
// 和本地bean一样使用service 此代理对象内部封装了所有通讯细节 服务端获得了远程服务的代理对象 像调用本地方法一样
DemoService demoService = reference.get();
String ret = demoService.sayHello("world");
System.out.println("ret=" + ret);
}
二 配置信息
public synchronized T get() {
if (this.destroyed) throw new IllegalStateException("Already destroyed!");
if (this.ref == null)
this.init();
return ref;
}
private void init() {
if (this.initialized) return; // 判断是否已经完成远程服务的初始化
this.initialized = true; // 标识完成远程服务的初始化
if (interfaceName == null || interfaceName.length() == 0)
throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
// get consumer's global configuration
this.checkDefault(); // 尝试在VM参数中加载ConsumerConfig配置项
appendProperties(this); // 尝试在VM参数中加载ReferenceConfig配置项
if (super.getGeneric() == null && this.getConsumer() != null) {
super.setGeneric(this.getConsumer().getGeneric());
}
if (ProtocolUtils.isGeneric(super.getGeneric())) { // 泛化调用
this.interfaceClass = GenericService.class;
} else {
try {
this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
super.checkInterfaceAndMethods(interfaceClass, this.methods); // 如果methods不为空 就校验interfaceClass是否存在对应的实现
}
String resolve = System.getProperty(interfaceName);
String resolveFile = null;
if (resolve == null || resolve.length() == 0) {
resolveFile = System.getProperty("dubbo.resolve.file");
if (resolveFile == null || resolveFile.length() == 0) {
File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
if (userResolveFile.exists()) {
resolveFile = userResolveFile.getAbsolutePath();
}
}
if (resolveFile != null && resolveFile.length() > 0) {
Properties properties = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(resolveFile));
properties.load(fis);
} catch (IOException e) {
throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e);
} finally {
try {
if (null != fis) fis.close();
} catch (IOException e) {
logger.warn(e.getMessage(), e);
}
}
resolve = properties.getProperty(interfaceName);
}
}
if (resolve != null && resolve.length() > 0) {
url = resolve;
if (logger.isWarnEnabled()) {
if (resolveFile != null) {
logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
} else {
logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
}
}
}
// 当前引用配置部分配置项如果缺失尝试把consumer的配置项赋值过来
if (this.consumer != null) {
if (this.application == null)
this.application = this.consumer.getApplication();
if (this.module == null)
module = this.consumer.getModule();
if (this.registries == null)
registries = this.consumer.getRegistries();
if (monitor == null)
monitor = consumer.getMonitor();
}
if (this.module != null) {
if (this.registries == null)
this.registries = this.module.getRegistries();
if (this.monitor == null)
this.monitor = this.module.getMonitor();
}
if (this.application != null) {
if (this.registries == null)
this.registries = this.application.getRegistries();
if (this.monitor == null)
this.monitor = this.application.getMonitor();
}
super.checkApplication();
checkStub(this.interfaceClass);
checkMock(this.interfaceClass);
Map<String, String> map = new HashMap<String, String>();
Map<Object, Object> attributes = new HashMap<Object, Object>();
map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);
map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
if (!super.isGeneric()) {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put("revision", revision);
}
String[] methods = Wrapper.getWrapper(this.interfaceClass).getMethodNames(); // 远程服务接口中的方法定义
if (methods.length == 0) {
logger.warn("NO method found in service interface " + interfaceClass.getName());
map.put("methods", Constants.ANY_VALUE);
} else {
map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
map.put(Constants.INTERFACE_KEY, interfaceName);
appendParameters(map, this.application);
appendParameters(map, module);
appendParameters(map, consumer, Constants.DEFAULT_KEY);
appendParameters(map, this);
String prefix = StringUtils.getServiceKey(map); // com.alibaba.dubbo.demo.DemoService
if (this.methods != null && !this.methods.isEmpty()) {
for (MethodConfig method : methods) {
appendParameters(map, method, method.getName());
String retryKey = method.getName() + ".retry";
if (map.containsKey(retryKey)) {
String retryValue = map.remove(retryKey);
if ("false".equals(retryValue)) {
map.put(method.getName() + ".retries", "0");
}
}
appendAttributes(attributes, method, prefix + "." + method.getName());
checkAndConvertImplicitConfig(method, map, attributes);
}
}
String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY);
if (hostToRegistry == null || hostToRegistry.length() == 0) {
hostToRegistry = NetUtils.getLocalHost();
} else if (isInvalidLocalHost(hostToRegistry)) {
throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
}
map.put(Constants.REGISTER_IP_KEY, hostToRegistry);
//attributes are stored by system context.
StaticContext.getSystemContext().putAll(attributes);
/**
* <p>map就是一个配置项 包含了远程服务的配置信息 根据配置信息构建远程服务的代理对象<ul>
* <li>side -> consumer</li>
* <li>application -> demo-service</li>
* <li>register.ip -> 192.168.0.3</li>
* <li>methods -> sayHello</li>
* <li>qos.port -> 33333</li>
* <li>dubbo -> 2.0.2</li>
* <li>pid -> 37888</li>
* <li>interface -> com.alibaba.dubbo.demo.DemoService</li>
* <li>timestamp -> 1652886744792</li>
* </ul></p>
*/
this.ref = this.createProxy(map);
ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel);
}
三 createProxy(...)
/**
* - 创建Invoker对象
* - 远程方式
* - 注册中心
* - zk
* - RegistryProtocol持有ZookeeperRegistry监听指定路径
* - configurators
* - routers
* - providers
* - RegistryProtocol获取到providers的子路径构建URL
* - DubboProtocol构建Invoker对象
* - 根据Invoker创建目标服务的代理对象
*/
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
private T createProxy(Map<String, String> map) {
URL tmpUrl = new URL("temp", "localhost", 0, map);
final boolean isJvmRefer; // false
if (super.isInjvm() == null) {
if (this.url != null && this.url.length() > 0) { // if a url is specified, don't do local reference // 指定了url配置 不做本地引用
isJvmRefer = false;
} else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { // 检测生产者自定义的配置是否需要本地引用
// by default, reference local service if there is
isJvmRefer = true;
} else {
isJvmRefer = false;
}
} else {
isJvmRefer = isInjvm().booleanValue();
}
if (isJvmRefer) { // 本地引用 生成本地引用URL 构建InjvmInvoker实例
URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
invoker = refprotocol.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
} else { // 远程引用
if (this.url != null && this.url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address. // 远程直连方式调用生产者服务
String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);
if (us != null && us.length > 0) {
for (String u : us) {
URL url = URL.valueOf(u);
if (url.getPath() == null || url.getPath().length() == 0) {
url = url.setPath(interfaceName);
}
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
} else {
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
} else { // assemble URL from register center's configuration // 远程调用 通过注册中心
/**
* 加载注册中心的url
* 启动消费者时指定的远程注册中心配置封装成URL
* 可能存在多协议/多注册中心
* url
* - registry://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=native-consumer&dubbo=2.0.2&pid=82343&qos.port=33333®istry=zookeeper×tamp=1669709199146
*/
List<URL> us = super.loadRegistries(false); //
if (us != null && !us.isEmpty()) {
for (URL u : us) {
URL monitorUrl = super.loadMonitor(u);
if (monitorUrl != null) {
map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
// refer参数
this.urls.add(u.addParameterAndEncoded(Constants.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.");
}
}
if (this.urls.size() == 1) { // 服务直连或者配置了单个注册中心
/**
* Protocol自适应扩展
* - 默认实现dubbo
* - URL协议类型
* 这里url
* - registry://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=native-consumer&dubbo=2.0.2&pid=82516&qos.port=33333&refer=application%3Dnative-consumer%26dubbo%3D2.0.2%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D82516%26qos.port%3D33333%26register.ip%3D198.18.0.1%26side%3Dconsumer%26timestamp%3D1669709307576®istry=zookeeper×tamp=1669709314764
* 因此实现是RegistryProtocol
*/
this.invoker = refprotocol.refer(interfaceClass, this.urls.get(0));
} else {
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
URL registryURL = null;
for (URL url : urls) {
invokers.add(refprotocol.refer(interfaceClass, url));
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
registryURL = url; // use last registry url
}
}
if (registryURL != null) { // registry url is available
// use AvailableCluster only when register's cluster is available
URL u = registryURL.addParameterIfAbsent(Constants.CLUSTER_KEY, AvailableCluster.NAME);
invoker = cluster.join(new StaticDirectory(u, invokers));
} else { // not a registry url
invoker = cluster.join(new StaticDirectory(invokers));
}
}
}
Boolean c = super.check;
if (c == null && this.consumer != null) {
c = consumer.isCheck();
}
if (c == null) {
c = true; // default true
}
if (c && !invoker.isAvailable()) { // invoker可用性检测
// make it possible for consumer to retry later if provider is temporarily unavailable
initialized = false; // com.alibaba.dubbo.demo.DemoService
final String serviceKey = (this.group == null ? "" : group + "/") + this.interfaceName + (this.version == null ? "" : ":" + this.version);
Set<ConsumerInvokerWrapper> consumerInvoker = ProviderConsumerRegTable.getConsumerInvoker(serviceKey);
if (consumerInvoker != Collections.<ConsumerInvokerWrapper>emptySet()) {
//since create proxy error , so we must be the first consumer. Simply clear ConcurrentHashSet
consumerInvoker.clear();
}
throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + serviceKey + " 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());
}
// create service proxy
/**
* 根据invoker生成代理类
*
* ProxyFactory自适应扩展
* - 默认实现javassist
* - URL中配置项proxy
* invoker中的URL
* - zookeeper://localhost:2181/com.alibaba.dubbo.registry.RegistryService?anyhost=true&application=native-consumer&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=82897&qos.port=33333®ister.ip=198.18.0.1&remote.timestamp=1669707577585&side=consumer×tamp=1669709866593
* 实现是JavassistProxyFactory
*/
return (T) proxyFactory.getProxy(this.invoker);
}
两个大步骤
- 创建Invoker对象
- 根据Invoker对象创建目标服务的代理对象
1 创建Invoker对象
创建Invoker对象(Protocol的RegistryProtocol实现中)
2 代理对象
通过Invoker对象创建目标服务的代理对象(ProxyFactory的JavassistProxyFactory)