五Dubbo服务引用源码分析--2创建远程调用的代理-2.1ReferenceBean.getObject
五Dubbo服务引用源码分析--2创建远程调用的代理-2.1ReferenceBean.getObject
5.1 创建远程调用的代理--getBean(DemoService.class)->getObject
在5.0消费端启动部分,已经分析了代理对象创建的时机:

getBean(DemoService.class)然后调用ReferenceBean.getObject方法,完成代理对象初始化
ReferenceBean
@Override
public Object getObject() throws Exception {
return get();
}
ReferenceConfig
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("Already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
TAG0 ReferenceConfig.init()
ReferenceConfig
private void init() {
if (initialized) {
return;
}
initialized = true;
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
}
//设置consumer的全局配置:如果consumerConfig为null,创建consumerConfig,并appendProperties(consumer)
checkDefault();
appendProperties(this); //完善传入的config内的setter属性
if (getGeneric() == null && getConsumer() != null) {
setGeneric(getConsumer().getGeneric());
}
if (ProtocolUtils.isGeneric(getGeneric())) {
interfaceClass = GenericService.class;
} else {
try {
//获取接口的类
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
checkInterfaceAndMethods(interfaceClass, methods);//检查methods是否在对应的接口中
}
/** …………………………………………………………………………………………resolveFile文件的创建、管理……………………………………………………………………………………………………………………*/
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 (consumer != null) {
if (application == null) { //applicationContext,是referenceBean中awareXX注入的属性
application = consumer.getApplication();
}
if (module == null) {
module = consumer.getModule();
}
if (registries == null) {
registries = consumer.getRegistries();
}
if (monitor == null) {
monitor = consumer.getMonitor();
}
}
if (module != null) {
if (registries == null) {
registries = module.getRegistries();
}
if (monitor == null) {
monitor = module.getMonitor();
}
}
if (application != null) {
if (registries == null) {
registries = application.getRegistries();
}
if (monitor == null) {
monitor = application.getMonitor();
}
}
checkApplication();
//????????
checkStubAndMock(interfaceClass);
/**………………………………………………………………………………………………………………检查配置,构建map………………………………………………………………………………………………………………………………………………… */
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 (!isGeneric()) {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put("revision", revision);
}
String[] methods = Wrapper.getWrapper(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); //将调用服务的接口名,放入map中
appendParameters(map, application);
appendParameters(map, module);
appendParameters(map, consumer, Constants.DEFAULT_KEY);
appendParameters(map, this);
String prefix = StringUtils.getServiceKey(map);
if (methods != null && !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);
}
}
//获取注册到registry的consumer端ip
String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY);
if (hostToRegistry == null || hostToRegistry.length() == 0) {
//192.168.0.101
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);
//TAG1 createProxy(map)
ref = createProxy(map);
ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel);
}
在init()方法中,是检查配置并将信息装配到map中,包括method、interface、register.ip等配置

TAG1 createProxy(map)
ReferenceConfig
private T createProxy(Map<String, String> map) {
/**…………………………………………………………………………………………………………………判断是否是本地引用……………………………………………………………………………………………………………………………… */
//创建临时url--temp://localhost?application=demotest-consumer&dubbo=2.0.2&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=92731&qos.enable=false®ister.ip=192.168.0.101&side=consumer×tamp=1672116260245
URL tmpUrl = new URL("temp", "localhost", 0, map);
final boolean isJvmRefer;
//目前,是根据url中scope=local,判断引用服务是在jvm中
if (isInjvm() == null) {//1
//url是referenceConfig内属性,如果初始化时指定,就不再执行本地引用,只远程调用
if (url != null && url.length() > 0) { //2
isJvmRefer = false;
} else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { //从map参数中看scope=local,为true
// by default, reference local service if there is
isJvmRefer = true;
} else {
isJvmRefer = false;
} //2
} else {
isJvmRefer = isInjvm().booleanValue();
} //1
/**………………………………………………………………本地引用……………………………………………………………………………………暂时略过 */
if (isJvmRefer) {
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 { //0
/** …………………………………………………………………………………………直连…………………………………………………………………………………………………………*/
//如果referenceConfig中初始化的url不为空(根据该初始化URL,直接引用---不需要配置中心,直连服务provider)
if (url != null && 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);//设置服务引用的path
}
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
} else {
//将referenceConfig中构造的map,合并到直连的url的参数对上去,然后添加到urls的list上
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
}
/**………………………………………………………… 从注册中心的configuration配置中,组装的服务端providerURL地址 ……………………………………………………………………*/
else { //1
//TAG1.1 loadRegistries(false) 加载注册中心url地址
//registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false®istry=zookeeper×tamp=1672207675233
List<URL> us = loadRegistries(false);
if (us != null && !us.isEmpty()) { //2
for (URL u : us) {
URL monitorUrl = loadMonitor(u);
if (monitorUrl != null) {
map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
//向注册中心中添加refer:encoded(map参数)的parameter,然后添加入List<url> urls中
//registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false&refer=application%3Ddemotest-consumer%26dubbo%3D2.0.2%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DgetPermissions%26organization%3Ddubbox%26owner%3Dprogrammer%26pid%3D92731%26qos.enable%3Dfalse%26register.ip%3D192.168.0.101%26side%3Dconsumer%26timestamp%3D1672116260245®istry=zookeeper×tamp=1672207675233
urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
}
} //2
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.");
}
}//1
//注册中心只有一个
if (urls.size() == 1) {
//TAG1.2 refprotocol.refer(interfaceClass, urls.get(0))
invoker = refprotocol.refer(interfaceClass, urls.get(0));
}
//注册中心多个(会refer多个invokers,然后需要cluster.join为一个)
else { //1
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
URL registryURL = null;
for (URL url : urls) { //2
//注册中心多个时,需要从每个注册中心中,protocol.refer构造invoker,并添加入invokers列表
invokers.add(refprotocol.refer(interfaceClass, url));
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
registryURL = url; // 使用最后一个注册中心地址
}
} //2
if (registryURL != null) { // 2 URLs中有注册中心
// use AvailableCluster only when register's cluster is available
URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
//TAG1.3 cluster.join(new StaticDirectory(u, invokers))
invoker = cluster.join(new StaticDirectory(u, invokers));
} else { // 如果URLs中,没有注册中心url
invoker = cluster.join(new StaticDirectory(invokers));
} //2
} //1
}//0
Boolean c = check;
if (c == null && consumer != null) {
c = consumer.isCheck();
}
if (c == null) {
c = true; // default true
}
if (c && !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());
}
//TAG1.4 proxyFactory.getProxy(invoker)
// create service proxy
return (T) proxyFactory.getProxy(invoker);
}
首先,ReferenceConfig内的属性:
public class ReferenceConfig<T> extends AbstractReferenceConfig {
//服务引用的protocol协议(protocol$Adaptive)
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private final List<URL> urls = new ArrayList<URL>();
private String interfaceName; //代理的接口名称
private Class<?> interfaceClass; //代理的接口类
private String client; //客户端名称类型
private String url; //端对端调用的URL
// method configs
private List<MethodConfig> methods;
// default config
private ConsumerConfig consumer;
private String protocol;
private transient volatile T ref; //构造的接口的代理对象
private transient volatile Invoker<?> invoker;
private transient volatile boolean initialized;
private transient volatile boolean destroyed;
createProxy(Map<String, String> map)逻辑如下:
1 根据传入的map,构造临时tmpurl;
2 从tmpurl中的scope,判断是否是本地引用isJvmRefer;
3.1 本地引用--略
3.2 远程引用
3.2.1 如果referenceConfig.url不为null,就是直连服务(直接给定provider端的url,可能是服务,可能是registryUrl);
3.2.2 如果referenceConfig.url为null:
step1:TAG1.1 loadRegistries(false) 获取注册中心地址;
step2:遍历注册中心地址,然后加入refer:encode(map),然后urls.add();
step3:判断urls.length==1
step3.1 是:TAG1.2 refprotocol.refer(interfaceClass, urls.get(0)) 构造invoker
step3.2 否(即为loadRegistry获取多个地址):
step3.2.1 判断urls中,是否有注册中心,即urls中是否有registry://的protocol协议头
1 有注册中心:TAG1.3 cluster.join(new StaticDirectory(u, invokers));
2 没有注册中心:cluster.join(new StaticDirectory(invokers))
区别上述两个方法
TAG1.1 loadRegistries(false)
AbstractInterfaceConfig
protected List<URL> loadRegistries(boolean provider) {
//如果有注册中心registryConfig,将referenceconfig内配置信息,追加到registry注册中心中
checkRegistry();
List<URL> registryList = new ArrayList<URL>();
//consumer.xml中配置的注册中心registryConfig
if (registries != null && !registries.isEmpty()) {
for (RegistryConfig config : registries) {
String address = config.getAddress(); //zookeeper://127.0.0.1:2181
if (address == null || address.length() == 0) {
address = Constants.ANYHOST_VALUE;
}
String sysaddress = System.getProperty("dubbo.registry.address"); //null
if (sysaddress != null && sysaddress.length() > 0) {
address = sysaddress;
}
if (address.length() > 0 && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
//构造注册中心url的map参数对
Map<String, String> map = new HashMap<String, String>();
appendParameters(map, application);
appendParameters(map, config);
map.put("path", RegistryService.class.getName()); //注册中心的path为RegistryService类路径
map.put("dubbo", 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 (!map.containsKey("protocol")) {
if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
map.put("protocol", "remote");
} else {
map.put("protocol", "dubbo"); //registry的protocol默认为dubbo
}
}
//根据address和map,解析并构造注册中心URL
//zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false×tamp=1672207675233
List<URL> urls = UrlUtils.parseURLs(address, map);
for (URL url : urls) {
//添加registry=zookeeper
url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
//设置注册中心url地址的协议头为registry://
//registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false®istry=zookeeper×tamp=1672207675233
url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
//provider=false,表示不是provider端,是consumer端
if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
|| (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
registryList.add(url);
}
}
}
}
}
return registryList;
}
主要逻辑是,根据注册中心的address+map,构造registryURL=registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-consumer&dubbo=2.0.2&organization=dubbox&owner=programmer&pid=92731&qos.enable=false®istry=zookeeper×tamp=1672207675233。
协议头为registry://,表示一个注册中心的服务。
TAG1.2 refprotocol.refer(interfaceClass, urls.get(0))--REFER
调用protocol.refer,生成核心的invoker对象。

public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
//registry
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//获取Protocol.class的扩展类名为registry的protocol
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
//REFER
return extension.refer(arg0, arg1);
}
由于Protocol在dubbo中有wrapper机制、filter过滤等,因此获取的registryProtocol外层包裹了ProtocolFilterWrapper、ProtocolListenerWrapper



浙公网安备 33010602011771号