在ReferenceBean中实现了InitializingBean、FactoryBean接口, 在bean实例化属性赋值之后会调用afterPropertiesSet方法, 获取bean时使用getObject方法, 并调用ReferenceConfig的init方法
public void afterPropertiesSet() throws Exception {
...
// 做了一顿初始化, 就是通过application/registry创建对象
...
}
init方法会为bean构建一个map, 然后创建代理对象
private T createProxy(Map<String, String> map) {
URL tmpUrl = new URL("temp", "localhost", 0, map);
boolean isJvmRefer;
if (this.isInjvm() == null) { // 判断是否为本地服务引用
if (this.url != null && this.url.length() > 0) {
isJvmRefer = false;
} else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
isJvmRefer = true;
} else {
isJvmRefer = false;
}
} else {
isJvmRefer = this.isInjvm();
}
if (isJvmRefer) {
// 如果是本地引用, 直接调用refer方法
URL url = (new URL("injvm", "127.0.0.1", 0, this.interfaceClass.getName())).addParameters(map);
this.invoker = refprotocol.refer(this.interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + this.interfaceClass.getName());
}
} else {
// 其他协议远程调用
URL u;
URL url;
if (this.url != null && this.url.length() > 0) {
// 从配置中心获取url 两种方式: 点对点 注册中心获取
String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(this.url);
if (us != null && us.length > 0) {
String[] arr$ = us;
int len$ = us.length;
for(int i$ = 0; i$ < len$; ++i$) {
String u = arr$[i$];
URL url = URL.valueOf(u);
if (url.getPath() == null || url.getPath().length() == 0) {
url = url.setPath(this.interfaceName);
}
// 如果是配置中心
if ("registry".equals(url.getProtocol())) {
this.urls.add(url.addParameterAndEncoded("refer", StringUtils.toQueryString(map)));
} else {
this.urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
} else {
// 如果在配置文件没有指定url 获取注册地址列表
List<URL> us = this.loadRegistries(false);
if (us != null && !us.isEmpty()) {
for(Iterator i$ = us.iterator(); i$.hasNext(); this.urls.add(u.addParameterAndEncoded("refer", StringUtils.toQueryString(map)))) {
u = (URL)i$.next();
// 监控中心地址
url = this.loadMonitor(u);
if (url != null) {
map.put("monitor", URL.encode(url.toFullString()));
}
}
}
if (this.urls.isEmpty()) {
throw new IllegalStateException("No such any registry to reference " + this.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) {
// 转换成invoker
this.invoker = refprotocol.refer(this.interfaceClass, (URL)this.urls.get(0));
} else {
List<Invoker<?>> invokers = new ArrayList();
URL registryURL = null;
Iterator i$ = this.urls.iterator();
while(i$.hasNext()) {
url = (URL)i$.next();
// 逐个转换
invokers.add(refprotocol.refer(this.interfaceClass, url));
if ("registry".equals(url.getProtocol())) {
registryURL = url;
}
}
if (registryURL != null) {
// 有注册中心url 使用availableCluster
u = registryURL.addParameter("cluster", "available");
this.invoker = cluster.join(new StaticDirectory(u, invokers)); // 合并
} else {
this.invoker = cluster.join(new StaticDirectory(invokers)); // 合并
}
}
}
...
}
看一下RegistryProtocol的refer方法
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
url = url.setProtocol(url.getParameter("registry", "dubbo")).removeParameter("registry");
Registry registry = this.registryFactory.getRegistry(url);
if (RegistryService.class.equals(type)) {
return this.proxyFactory.getInvoker(registry, type, url);
} else {
Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded("refer"));
String group = (String)qs.get("group"); // 获取group参数
return group == null || group.length() <= 0 || Constants.COMMA_SPLIT_PATTERN.split(group).length <= 1 && !"*".equals(group) ? this.doRefer(this.cluster, registry, type, url) : this.doRefer(this.getMergeableCluster(), registry, type, url);
}
}
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
RegistryDirectory<T> directory = new RegistryDirectory(type, url);
directory.setRegistry(registry);
directory.setProtocol(this.protocol);
Map<String, String> parameters = new HashMap(directory.getUrl().getParameters());
URL subscribeUrl = new URL("consumer", (String)parameters.remove("register.ip"), 0, type.getName(), parameters);
if (!"*".equals(url.getServiceInterface()) && url.getParameter("register", true)) {
// 如果是注册url. 注册消费者, 向zk创建节点
registry.register(subscribeUrl.addParameters(new String[]{"category", "consumers", "check", String.valueOf(false)}));
}
// 订阅对应目录
directory.subscribe(subscribeUrl.addParameter("category", "providers,configurators,routers"));
Invoker invoker = cluster.join(directory);
ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
return invoker;
}
查看RegistryDirectory.subscribe订阅方法
public void subscribe(URL url) {
this.setConsumerUrl(url);
this.registry.subscribe(url, this); // 将自己当做listener传给zk 实现了NotifyListener接口
}
// 当有订阅的相关目录产生变化后, 会调用此方法
public synchronized void notify(List<URL> urls) {
// 获取以下信息
List<URL> invokerUrls = new ArrayList();
List<URL> routerUrls = new ArrayList();
List<URL> configuratorUrls = new ArrayList();
Iterator i$ = urls.iterator();
while(true) {
while(true) {
while(i$.hasNext()) {
URL url = (URL)i$.next();
String protocol = url.getProtocol();
String category = url.getParameter("category", "providers");
if (!"routers".equals(category) && !"route".equals(protocol)) {
if (!"configurators".equals(category) && !"override".equals(protocol)) {
if ("providers".equals(category)) {
invokerUrls.add(url);
} else {
logger.warn("Unsupported category " + category + " in notified url: " + url + " from registry " + this.getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost());
}
} else {
configuratorUrls.add(url);
}
} else {
routerUrls.add(url);
}
}
if (configuratorUrls != null && !configuratorUrls.isEmpty()) {
this.configurators = toConfigurators(configuratorUrls);
}
List localConfigurators;
if (routerUrls != null && !routerUrls.isEmpty()) {
localConfigurators = this.toRouters(routerUrls);
if (localConfigurators != null) {
this.setRouters(localConfigurators);
}
}
localConfigurators = this.configurators;
this.overrideDirectoryUrl = this.directoryUrl;
Configurator configurator;
if (localConfigurators != null && !localConfigurators.isEmpty()) {
for(Iterator i$ = localConfigurators.iterator(); i$.hasNext(); this.overrideDirectoryUrl = configurator.configure(this.overrideDirectoryUrl)) {
configurator = (Configurator)i$.next();
}
}
// 刷新Invoker
this.refreshInvoker(invokerUrls);
return;
}
}
}
刷新invoker会调用DubboProtocol的refer方法
方法内会根据url信息创建netty客户端, 用于通讯, 至此服务引用完成
参考
添加链接描述