一、Dubbo服务引用流程简述
ReferenceBean实现了FactoryBean接口,当对任意服务interface进行自动注入或者getBean获取时,就会触发getObject()函数的服务引用过程。
- 本地引入走injvm协议,到服务暴露的缓存中取exporter。
- 直连远程引入服务,不需要启动注册中心,由consumer直接配置写死provider地址,然后直连即可。
- 注册中心引入远程服务,consumer通过注册中心得知provider的相关信息,然后进行服务的引入。
获取注册中心实例,向注册中心注册自身,并订阅providers,configurators,routers节点,触发DubboInvoker生成,cluster将多个服务调用者进行封装,返回一个invoker。
通过Dubbo配置构建一个map, 然后利用map来构建URL,再通过URL上的协议利用SPI机制调用对应的protocol.refer得到对应的invoker。然后再构建代理,封装invoker返回服务引用,之后consumer调用这个代理类。
二、 Dubbo服务引用懒汉式流程
- ReferenceBean实现了FactoryBean接口,InitializingBean接口。有两种方式引用:饿汉式、懒汉式。
- 懒汉式:只用当这个服务被注入到其他类中时启动引入流程,也就是说用到了才会开始服务引用。利用FactoryBean的getObject()获取。
- 饿汉式:实现了InitializingBean的afterPropertiesSet()方法,通过调用该方法引入服务。
- 默认使用懒汉式。如果需要使用饿汉式,可通过配置dubbo:reference的Init属性开启。
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
//懒汉式引用服务提供者
public Object getObject() {
return this.get();
}
//饿汉式引用服务提供者
public void afterPropertiesSet() throws Exception {
this.prepareDubboConfigBeans();
if (this.init == null) {
this.init = false;
}
if (this.shouldInit()) {
this.getObject();
}
}
}
- ReferenceConfig初始化provider.
public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
//通过SPI机制找到Protocol实现类。(1)如果有注册中心,找到RegistryProtocol。(2)找到协议Protocol实现类。
private static final Protocol REF_PROTOCOL = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
public synchronized T get() {
if (this.ref == null) {
//初始化服务提供者
this.init();
}
return this.ref;
}
public synchronized void init() {
if (!this.initialized) {
Map<String, String> map = new HashMap();
map.put("side", "consumer");
...
...
//上面操作都是往map中放值,map中存的是服务提供者的信息,比如:注册中心地址,调用服务提供者接口名,调用方法名,version等。
//创建代理对象
this.ref = this.createProxy(map);
...
}
}
/**
* 创建代理
*/
private T createProxy(Map<String, String> map) {
URL u;
if (this.shouldJvmRefer(map)) {
URL url = (new URL("injvm", "127.0.0.1", 0, this.interfaceClass.getName())).addParameters(map);
this.invoker = REF_PROTOCOL.refer(this.interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + this.interfaceClass.getName());
}
} else {
//省略代码
...
...
if (this.urls.size() == 1) {
//this.urls: 注册中心的地址
//this.interfaceClass: provider接口
//REF_PROTOCOL:通过SPI机制获取实现类。
//从注册中心找到provider
this.invoker = REF_PROTOCOL.refer(this.interfaceClass, (URL)this.urls.get(0));
} else {
List<Invoker<?>> invokers = new ArrayList();
URL registryURL = null;
Iterator var16 = this.urls.iterator();
while(var16.hasNext()) {
monitorUrl = (URL)var16.next();
invokers.add(REF_PROTOCOL.refer(this.interfaceClass, monitorUrl));
if (UrlUtils.isRegistry(monitorUrl)) {
registryURL = monitorUrl;
}
}
String cluster;
if (registryURL != null) {
cluster = registryURL.getParameter("cluster", "zone-aware");
this.invoker = Cluster.getCluster(cluster, false).join(new StaticDirectory(registryURL, invokers));
} else {
cluster = CollectionUtils.isNotEmpty(invokers) ? (((Invoker)invokers.get(0)).getUrl() != null ? ((Invoker)invokers.get(0)).getUrl().getParameter("cluster", "zone-aware") : "failover") : "failover";
this.invoker = Cluster.getCluster(cluster).join(new StaticDirectory(invokers));
}
}
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + this.interfaceClass.getName() + " from url " + this.invoker.getUrl());
}
String metadata = (String)map.get("metadata-type");
WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? "local" : metadata);
if (metadataService != null) {
u = new URL("consumer", (String)map.remove("register.ip"), 0, (String)map.get("interface"), map);
metadataService.publishServiceDefinition(u);
}
return PROXY_FACTORY.getProxy(this.invoker, ProtocolUtils.isGeneric(this.generic));
}
}
- RegistryProtocol从注册中心订阅服务。
public class RegistryProtocol implements Protocol {
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
url = this.getRegistryUrl(url);
//获取注册中心
Registry registry = this.registryFactory.getRegistry(url);
//省略代码
...
...
return this.doRefer(cluster, 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);
URL subscribeUrl = new URL("consumer", (String)parameters.remove("register.ip"), 0, type.getName(), parameters);
//省略代码
...
...
//订阅服务
directory.subscribe(toSubscribeUrl(subscribeUrl));
//省略代码
...
}
}
- DubboProtocol获取Netty客户端。
public abstract class AbstractProtocol implements Protocol {
//获取服务引用
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
return new AsyncToSyncInvoker(this.protocolBindingRefer(type, url));
}
}
public class DubboProtocol extends AbstractProtocol {
//获取服务引用
public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
//getClients获取Netty客户端
DubboInvoker<T> invoker = new DubboInvoker(serviceType, url, this.getClients(url), this.invokers);
this.invokers.add(invoker);
return invoker;
}
//获取客户端
private ExchangeClient[] getClients(URL url) {
boolean useShareConnect = false;
int connections = url.getParameter("connections", 0);
List<ReferenceCountExchangeClient> shareClients = null;
if (connections == 0) {
useShareConnect = true;
String shareConnectionsStr = url.getParameter("shareconnections", (String)null);
connections = Integer.parseInt(StringUtils.isBlank(shareConnectionsStr) ? ConfigUtils.getProperty("shareconnections", "1") : shareConnectionsStr);
//获取共享客户端
shareClients = this.getSharedClient(url, connections);
}
//连接有多个,创建多个客户端
ExchangeClient[] clients = new ExchangeClient[connections];
for(int i = 0; i < clients.length; ++i) {
if (useShareConnect) {
//获取共享客户端
clients[i] = (ExchangeClient)shareClients.get(i);
} else {
clients[i] = this.initClient(url);
}
}
return clients;
}
//获取共享客户端
private List<ReferenceCountExchangeClient> getSharedClient(URL url, int connectNum) {
String key = url.getAddress();
//先从缓存中获取
List<ReferenceCountExchangeClient> clients = (List)this.referenceClientMap.get(key);
//双重检查锁定
if (this.checkClientCanUse(clients)) {
this.batchClientRefIncr(clients);
return clients;
} else {
//使用锁
this.locks.putIfAbsent(key, new Object());
synchronized(this.locks.get(key)) {
clients = (List)this.referenceClientMap.get(key);
//双重检查锁定
if (this.checkClientCanUse(clients)) {
this.batchClientRefIncr(clients);
return clients;
} else {
if (CollectionUtils.isEmpty(clients)) {
clients = this.buildReferenceCountExchangeClientList(url, connectNum);
this.referenceClientMap.put(key, clients);
}
this.locks.remove(key);
return clients;
}
}
}
}
private ReferenceCountExchangeClient buildReferenceCountExchangeClient(URL url) {
//初始化客户端
ExchangeClient exchangeClient = this.initClient(url);
return new ReferenceCountExchangeClient(exchangeClient);
}
private ExchangeClient initClient(URL url) {
String str = url.getParameter("client", url.getParameter("server", "netty"));
url = url.addParameter("codec", "dubbo");
url = url.addParameterIfAbsent("heartbeat", String.valueOf(60000));
//用Exchanger进行connect
client = Exchangers.connect(url, this.requestHandler);
return (ExchangeClient)client;
}
}
- Exchanger连接Netty客户端。
public class Exchangers {
public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
url = url.addParameterIfAbsent("codec", "exchange");
return getExchanger(url).connect(url, handler);
}
}
public class HeaderExchanger implements Exchanger {
public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeClient(Transporters.connect(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))}), true);
}
}
public class Transporters {
public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
return getTransporter().connect(url, (ChannelHandler)handler);
}
}
@SPI("netty")
public interface Transporter {
@Adaptive({"server", "transporter"})
RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;
@Adaptive({"client", "transporter"})
Client connect(URL url, ChannelHandler handler) throws RemotingException;
}
- 连接Netty客户端之后,拿到invoker。
public class DubboProtocol extends AbstractProtocol {
public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
//连接客户端,封装成invoker
DubboInvoker<T> invoker = new DubboInvoker(serviceType, url, this.getClients(url), this.invokers);
//拿到invoker
this.invokers.add(invoker);
return invoker;
}
}
- 获取到Invoker之后,将消费者信息注册到ProviderConsumerRegTable中。
public class RegistryProtocol implements Protocol {
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
//省略代码
...
...
//订阅服务
directory.subscribe(toSubscribeUrl(subscribeUrl));
Invoker<T> invoker = cluster.join(directory);
//获取监听器
List<RegistryProtocolListener> listeners = this.findRegistryProtocolListeners(url);
RegistryInvokerWrapper<T> registryInvokerWrapper = new RegistryInvokerWrapper(directory, cluster, invoker);
Iterator var11 = listeners.iterator();
while(var11.hasNext()) {
RegistryProtocolListener listener = (RegistryProtocolListener)var11.next();
listener.onRefer(this, registryInvokerWrapper);
}
return registryInvokerWrapper;
}
}