服务发现
Dubbo服务引用分两种:饿汉式和懒汉式,默认使用的时懒汉式。第一种饿汉式在Spring容器初始化时,调用ReferenceBean
的afterPropertiesSet
方法时引用服务;第二种懒汉式,在对应服务被注入到其他类中时,Spring会调用getObject()
方法,完成服务引用。
有三种引用服务方式:引用本地服务,通过直接连接引用远程服务,通过注册中心引用远程服务。无论哪种方式,最后都可以获得一个或一组Invoker实例。对于一组Invoker实例,会交由AbstractClusterInvoker
管理,对于一组Invoker,AbstractClusterInvoker
内部会根据配置的LoadBalance
策略进行负载均衡。
Zookeeper中的消费者注册和节点订阅
消费者在向注册中心注册消费者的时候,还会订阅节点的变更。
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
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 subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {
directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url));
//向注册中心注册消费者
registry.register(directory.getRegisteredConsumerUrl());
}
directory.buildRouterChain(subscribeUrl);
//订阅节点,然后notify,然后刷新invokers列表
directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));
//通过注册中心拿到的provider可能会有多个,在这里合并
Invoker invoker = cluster.join(directory);
ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
return invoker;
}
register就是向注册中心注册,不通的注册中心实现也不尽相同,zk就是创建一个临时节点(provider创建的是永久节点)。订阅的话,zookeeper就是添加子节点监听事件。
动态代理和回声测试
Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它。 它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
invoker创建完以后,需要的就是代理对象,我们通过代理对象发起调用。
生成的代理对象,除了实现了provider提供的接口,还实现了EchoService
。EchoService
是用于检测服务是否可用的。
if (interfaces == null) {
interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
}