引言
在调用远程服务时就像调用本地方法一样,其内部究竟是如何实现的呢???
如:在项目xml中定义
<dubbo :reference interface ="com.fei.sys.ICarProvider" id ="carProvider" init ="false" />
然后引用
@Resource
private ICarProvider carProvider;
再调用
carProvider.sayHello();
那么我们就来看看消费者是如何进行服务调用的
创建代理类
Dubbo加载referenceBean的流程 1、解析在DubboNamespaceHandler把配置解析成为BeanDefine对象 2、走spring对象初始化、实例化
ReferenceBean 类的内容非常丰富,逻辑也比较复杂,但是归根结底主要有三个功能,分别是配置初始化、服务订阅和创建代理对象。
下图是ReferenceBean类的继承结构。
从图中看到 ReferenceBean 继承了ReferenceConfig类,实现了FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean这些接口。
FactoryBean:简单工厂一般用在初始化比较复杂的对象,此处主要在返回对远程服务调用的代理类的实现
ApplicationContextAware:实现此接口可以得到ApplicationContext中的所有Bean
InitializingBean:为Bean提供初始化方式,afterPropertiesSet在初始化时都会执行
DisposableBean:提供销毁的方法,在Bean销毁时能够回调执行
dubbo核心类ReferenceConfig继承了AbstractReferenceConfig、AbstractInterfaceConfig、AbstractMethodConfig、AbstractConfig
AbstractConfig:配置解析的工具方法和公用方法
AbstractMethodConfig:封装了配置文件标签中方法级别的相关属性
AbstractInterfaceConfig:封装了配置文件标签中接口级别的相关属性
AbstractReferenceConfig:封装了引用实例的默认配置,比如检查服务实例是否存在,是否使用泛化接口
ReferenceConfig:封装了全局配置,包括接口名、方法配置、默认配置
配置初始化
在ReferenceBean的afterPropertiesSet方法中
public void afterPropertiesSet() throws Exception {
if (this.applicationContext != null) {
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ConfigCenterBean.class, false, false);
}
Map monitorConfigMap;
Iterator var3;
//如果consumer未注册,则执行
if (this.getConsumer() == null) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ConsumerConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
ConsumerConfig consumerConfig = null;
var3 = monitorConfigMap.values().iterator();
label267:
while(true) {
ConsumerConfig config;
do {
if (!var3.hasNext()) {
if (consumerConfig != null) {
this.setConsumer(consumerConfig);
}
break label267;
}
config = (ConsumerConfig)var3.next();
} while(config.isDefault() != null && !config.isDefault().booleanValue());
if (consumerConfig != null) {
throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config);
}
consumerConfig = config;
}
}
}
if (this.getApplication() == null && (this.getConsumer() == null || this.getConsumer().getApplication() == null)) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ApplicationConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
ApplicationConfig applicationConfig = null;
ApplicationConfig config;
for(var3 = monitorConfigMap.values().iterator(); var3.hasNext(); applicationConfig = config) {
config = (ApplicationConfig)var3.next();
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
}
if (applicationConfig != null) {
this.setApplication(applicationConfig);
}
}
}
if (this.getModule() == null && (this.getConsumer() == null || this.getConsumer().getModule() == null)) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ModuleConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
ModuleConfig moduleConfig = null;
var3 = monitorConfigMap.values().iterator();
label231:
while(true) {
ModuleConfig config;
do {
if (!var3.hasNext()) {
if (moduleConfig != null) {
this.setModule(moduleConfig);
}
break label231;
}
config = (ModuleConfig)var3.next();
} while(config.isDefault() != null && !config.isDefault().booleanValue());
if (moduleConfig != null) {
throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
}
moduleConfig = config;
}
}
}
if (StringUtils.isEmpty(this.getRegistryIds())) {
if (this.getApplication() != null && StringUtils.isNotEmpty(this.getApplication().getRegistryIds())) {
this.setRegistryIds(this.getApplication().getRegistryIds());
}
if (this.getConsumer() != null && StringUtils.isNotEmpty(this.getConsumer().getRegistryIds())) {
this.setRegistryIds(this.getConsumer().getRegistryIds());
}
}
if (CollectionUtils.isEmpty(this.getRegistries()) && (this.getConsumer() == null || CollectionUtils.isEmpty(this.getConsumer().getRegistries())) && (this.getApplication() == null || CollectionUtils.isEmpty(this.getApplication().getRegistries()))) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, RegistryConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
List<RegistryConfig> registryConfigs = new ArrayList();
if (StringUtils.isNotEmpty(this.registryIds)) {
Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(this.registryIds)).forEach((id) -> {
if (monitorConfigMap.containsKey(id)) {
registryConfigs.add(monitorConfigMap.get(id));
}
});
}
if (registryConfigs.isEmpty()) {
var3 = monitorConfigMap.values().iterator();
while(var3.hasNext()) {
RegistryConfig config = (RegistryConfig)var3.next();
if (StringUtils.isEmpty(this.registryIds)) {
registryConfigs.add(config);
}
}
}
if (!registryConfigs.isEmpty()) {
super.setRegistries(registryConfigs);
}
}
}
if (this.getMetadataReportConfig() == null) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, MetadataReportConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() == 1) {
super.setMetadataReportConfig((MetadataReportConfig)monitorConfigMap.values().iterator().next());
} else if (monitorConfigMap != null && monitorConfigMap.size() > 1) {
throw new IllegalStateException("Multiple MetadataReport configs: " + monitorConfigMap);
}
}
if (this.getConfigCenter() == null) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ConfigCenterConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() == 1) {
super.setConfigCenter((ConfigCenterConfig)monitorConfigMap.values().iterator().next());
} else if (monitorConfigMap != null && monitorConfigMap.size() > 1) {
throw new IllegalStateException("Multiple ConfigCenter found:" + monitorConfigMap);
}
}
if (this.getMonitor() == null && (this.getConsumer() == null || this.getConsumer().getMonitor() == null) && (this.getApplication() == null || this.getApplication().getMonitor() == null)) {
monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, MonitorConfig.class, false, false);
if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
MonitorConfig monitorConfig = null;
var3 = monitorConfigMap.values().iterator();
label169:
while(true) {
MonitorConfig config;
do {
if (!var3.hasNext()) {
if (monitorConfig != null) {
this.setMonitor(monitorConfig);
}
break label169;
}
config = (MonitorConfig)var3.next();
} while(config.isDefault() != null && !config.isDefault().booleanValue());
if (monitorConfig != null) {
throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
}
monitorConfig = config;
}
}
}
if (this.shouldInit()) {
this.getObject();
}
}
在这一步其实就是的默认配置
consumer:dubbo:consumer 当reference某些属性没有配置的时候就可以采用默认配置
application:应用配置,用于配置当前应用信息
module:模块配置,用于配置当前模块信息,可选
registries:注册中心配置,用于配置连接注册中心相关信息
monitor:监控中心配置,用于配置连接监控中心相关信息,可选
方法的最后一行有一行 this.getObject(),调用FactoryBean的getObject方法,里面会调用ReferenceConfig的init方法进行数据组装,服务订阅,创建代理。
否则是在实际引用类时执行FactoryBean的getObject方法。
服务订阅
在getObject方法中如果代理对象未被创建值执行初始化 init()
public synchronized T get() {
checkAndUpdateSubConfigs();
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
在初始化方法中先组装参数如下
private T createProxy(Map<String, String> map) {
if (shouldJvmRefer(map)) {
URL url = new URL(Constants.LOCAL_PROTOCOL, Constants.LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
invoker = refprotocol.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
} else {
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 (StringUtils.isEmpty(url.getPath())) {
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
//配置中心初始化
checkRegistry();
List<URL> us = loadRegistries(false);
if (CollectionUtils.isNotEmpty(us)) {
for (URL u : us) {
URL monitorUrl = loadMonitor(u);
if (monitorUrl != null) {
map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
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 (urls.size() == 1) {
invoker = refprotocol.refer(interfaceClass, 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 RegistryAwareCluster only when register's cluster is available
URL u = registryURL.addParameter(Constants.CLUSTER_KEY, RegistryAwareCluster.NAME);
// The invoker wrap relation would be: RegistryAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker
invoker = cluster.join(new StaticDirectory(u, invokers));
} else { // not a registry url, must be direct invoke.
invoker = cluster.join(new StaticDirectory(invokers));
}
}
}
if (shouldCheck() && !invoker.isAvailable()) {
// make it possible for consumer to retry later if provider is temporarily unavailable
initialized = false;
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());
}
/**
* @since 2.7.0
* ServiceData Store
*/
MetadataReportService metadataReportService = null;
if ((metadataReportService = getMetadataReportService()) != null) {
URL consumerURL = new URL(Constants.CONSUMER_PROTOCOL, map.remove(Constants.REGISTER_IP_KEY), 0, map.get(Constants.INTERFACE_KEY), map);
metadataReportService.publishConsumer(consumerURL);
}
// create service proxy
return (T) proxyFactory.getProxy(invoker);
}
在执行创建代理对象 ref = createProxy(map); 此方法主要做的事有
- 判断当前服务是本地服务还是远程服务,本地服务生成 InjvmInvoker
- 是否是用户指定URL调用,不是则检查注册表配置是否存在,然后将其转换为链接,如果是zookeeper则连接注册中心。
- loadRegistrie()根据注册中心装入 registry URl, 将zookeeper url协议更换为registry URl。
- 与注册中心进行交互,watch相应的节点
**
在方法 invoker = refprotocol.refer(interfaceClass, urls.get(0));
这段代码通过SPI机制获取到 Protocol 执行对象,执行过程是 ProtocolFilterWrapper → ProtocolListenerWrapper → RegistryProtocol
META-INF\dubbo\internal\org.apache.dubbo.rpc.Protocol
ProtocolFilterWrapper :过滤器调用链包装器
ProtocolListenerWrapper:监听器调用链包装器
RegistryProtocol:注册协议完成服务订阅
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
//将ZookeeperRegistry注入到RegistryDirectory中
directory.setRegistry(registry);
directory.setProtocol(protocol);
// all attributes of REFER_KEY
Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
//生成consumer端的URL协议,consumer://
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));
//调用ZookeeperRegistry实例进行消费组地址注册
registry.register(directory.getRegisteredConsumerUrl());
}
directory.buildRouterChain(subscribeUrl);
//服务订阅
directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));
Invoker invoker = cluster.join(directory);
ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
return invoker;
}
通过调用ZookeeperRegistry.doSubscribe方法实现消费者的地址注册和监听/dubbo/com.xxx.xxx/providers
最终调用 client.getChildren().usingWatcher(listener).forPath(path) 实现服务订阅
org.apache.dubbo.registry.integration.RegistryDirectory#notify 注册中心发生变化会触发此方法刷新本地注册表
创建代理对象
在配置初始化与订阅完成后,剩下的工作就是对服务接口进行包装,产生代理对象并返回。
*// create service proxy
*return (T) proxyFactory.getProxy(invoker);
Dubbo实现代理对象有两种方式,一种是JDK动态代理,使用的是JdkProxyFactory,另一种是使用Javassit字节码来实现,使用的是JavassistProxyFactory来实现,默认使用的是JavassistProxyFactory。
远程调用
前面是生成了ReferenceBean生成代理对象的流程,下面是如果通过代理对象进行方法的调用流程,从大的方面讲是代理调用,容错负载和远程通信。
执行过程
ReferenceAnnotationBeanPostProcessor →
InvokerInvocationHandler →
MockClusterInvoker →
FailoverClusterInvoker(负载均衡处理)
ListenerInvokerWrapper(监听器) →
ProtocolFilterWrapper(过滤器逻辑处理)
DubboInvoker(执行dubbo执行器)
HeaderExchangeChannel
请求方法
public ResponseFuture request(Object request, int timeout) throws RemotingException {
if (closed) {
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
//新建一个请求对象,构造方法会生成一个自增的唯一ID
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
req.setData(request);
//新建一个Future对象
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);
try {
//发送请求,进行远程调用
channel.send(req);
} catch (RemotingException e) {
future.cancel();
throw e;
}
//返回Future
return future;
}
看看DefaultFuture的get方法和receive方法
public Object get(int timeout) throws RemotingException {
if (timeout <= 0) {
timeout = Constants.DEFAULT_TIMEOUT;
}
//请求未返回时
if (!isDone()) {
long start = System.currentTimeMillis();
//上锁
lock.lock();
try {
while (!isDone()) {
//设置等待超时时间,请求返回时会唤醒
done.await(timeout, TimeUnit.MILLISECONDS);
if (isDone() || System.currentTimeMillis() - start > timeout) {
break;
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
if (!isDone()) {
throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
}
}
//获取返回值
return returnFromResponse();
}
private void doReceived(Response res) {
//上锁
lock.lock();
try {
response = res;
if (done != null) {
//环境线程
done.signal();
}
} finally {
lock.unlock();
}
if (callback != null) {
invokeCallback(callback);
}
}
\