dubbo版本:2.7.2
一、spring解析自定义扩展标签。
spring分析xml节点的可以看出对于自定义命名空间的节点使用的是自定义的NameSpaceHandler处理的。
在spring初始化的时候,创建DefaultBeanDefinitionDocumentReader的时候,指明了会从META-INF/spring.handlers中加载各类自定义扩展标签对应的处理器。
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
在dubbo的jar包里有META-INF/spring.handlers制定了dubbo命名空间的namespaceHandler。
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
DefaultBeanDefinitionDocumentReader
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
// 自定义命名空间在这里解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
// 这里会获得之前从dubbo的META-INF/spring.handlers加载的dubbo命名空间解析器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
针对每一个dubbo自定义标签注册乐解析器。除了annotation注解,解析器都是DubboBeanDefinitionParser。DubboBeanDefinitionParser(ApplicationConfig.class, true)第一个参数是最终会解析成的bean的类型,第二个参数是否required。
除了service、reference、config-center标签会解析成Bean类,其他都是解析成Cofig类。因为这三个比较复杂。
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
@Override
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
}
DubboBeanDefinitionParser的parse方法,都是一些把配置文件分析成BeanDefinition的逻辑,普通的spring bean 在parse阶段也是分析成beanDefinition,beanDefinition到最终的注入spring的bean需要执行哪些逻辑,就看bean实现了哪些spring的接口了。
private static BeanDefinition parse(Element element, ParserContext parserContext, Class> beanClass, boolean required) {
所以先看service标签对应的ServiceBean类。
InitializingBean接口:初始化bean后会调用afterPropertiesSet方法。
DisposableBean接口:销毁bean会调用destroy方法。这里什么都没做。
ApplicationContextAware接口:注入applicationContext对象。
ApplicationListener接口:事件发布。
其他的aware接口:都是注入spring的对象。
public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean,
ApplicationContextAware, ApplicationListener, BeanNameAware,
ApplicationEventPublisherAware
先看afterPropertiesSet方法。
serviceBean继承了ServiceConfig,ServiceConfig继承很多Config类。因为很多类都需要比如application、registries、protocal这些配置信息,而且公用了很多配置信息相关的逻辑。所以产生这么多层继承关系。
afterPropertiesSet就是从spring容器获取providerConfigs、application、module、Registry、等等,然后填充成员变量,便于后续使用。
截取一部分代码
public void afterPropertiesSet() throws Exception {
// 第一次provider肯定是空
if (getProvider() == null) {
// 从spring容器中获取ProviderConfig类
Map providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
if (providerConfigMap != null && providerConfigMap.size() > 0) {
Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
if (CollectionUtils.isEmptyMap(protocolConfigMap)
&& providerConfigMap.size() > 1) { // backward compatibility
List providerConfigs = new ArrayList();
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() != null && config.isDefault()) {
providerConfigs.add(config);
}
}
if (!providerConfigs.isEmpty()) {
// 赋值到config成员变量中
setProviders(providerConfigs);
}
} else {
ProviderConfig providerConfig = null;
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() == null || config.isDefault()) {
if (providerConfig != null) {
throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
}
providerConfig = config;
}
}
if (providerConfig != null) {
setProvider(providerConfig);
}
}
}
...一系列类似的从spring中获取dubbo所需的配置类填充config成员变量
// 如果不支持事件发布,这里就直接export导出服务。因为一般导出服务是在事件监听中做的
if (!supportedApplicationListener) {
export();
}
}
事件监听方法,监听spring refresh事件,这里导出服务。
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
@Override
public void export() {
super.export();
// Publish ServiceBeanExportedEvent
publishExportEvent();
}
public synchronized void export() {
// 检查更新配置信息,这里就是一些校验和一些赋值配置信息逻辑,链接注册中心,暂时不看
checkAndUpdateSubConfigs();
// 是否export,因为dubbo服务可以配置export=false
if (!shouldExport()) {
return;
}
// 是否延迟导出,延迟就是简单的定时器
if (shouldDelay()) {
delayExportExecutor.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
} else {
doExport();
}
}
private void doExportUrls() {
// 根据之前已经afterPropertiesSet方法已经填充好的的成员变量registry注册中心对象,再根据application、prtocal等构造一个URL对象。
// 如:registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=first-dubbo-provider&dubbo=2.0.2&pid=21772®istry=zookeeper&release=2.7.2×tamp=1635649541098
List registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
// 如果group和version不为空,protocal的contextPath也不为空,则根据他们组装成pathKey
// 为空则还是path:org.apache.dubbo.samples.api.GreetingsService
String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
// providerModel,每提供的一个服务service类,封装成一个providerModel模型,providerModel会把service类相关信息serviceName、serviceInstance、serviceInterfaceClass、methods解析和维护起来
ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
// ApplicationModel是以key,value形式维护providerModel
ApplicationModel.initProviderModel(pathKey, providerModel);
// 真正导出服务
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
导出服务:可以预见两步:1、先netty开启端口暴露服务,使得其他服务可以调用。2、把服务url注册到zookeeper上。
protocolConfig自然是前面解析配置文件的时候的Dubbo协议。
registryURLs只有一个::registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=first-dubboprovider&dubbo=2.0.2&pid=21772®istry=zookeeper&release=2.7.2×tamp=1635649541098
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {
String name = protocolConfig.getName();
if (StringUtils.isEmpty(name)) {
name = DUBBO;
}
// 把各种配置参数放到map
Map map = new HashMap();
map.put(SIDE_KEY, PROVIDER_SIDE);
appendRuntimeParameters(map);
appendParameters(map, metrics);
appendParameters(map, application);
appendParameters(map, module);
// remove 'default.' prefix for configs from ProviderConfig
// appendParameters(map, provider, Constants.DEFAULT_KEY);
appendParameters(map, provider);
appendParameters(map, protocolConfig);
appendParameters(map, this);
// methods是否为空。配置的时候,里面可以显示指定method。指定了解析的时候就会给methods赋值。这里没有
if (CollectionUtils.isNotEmpty(methods)) {
}
// 是否是一般协议,这里是false。不管
if (ProtocolUtils.isGeneric(是否是一般协议,这里是false。不管)) {
map.put(GENERIC_KEY, generic);
map.put(METHODS_KEY, ANY_VALUE);
}else {
// 如果配置了版本这里就添加版本,这里没配置跳过。
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
// Wrapper会动态javassiter生成代理类。代理类包含了很多类参数,比如methodName就是其中一个参数,反射扫描类的所有方法。最后添加到map中。
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("No method found in service interface " + interfaceClass.getName());
map.put(METHODS_KEY, ANY_VALUE);
} else {
map.put(METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
}
}
// 构造export的服务url,根据之前获取的各种参数
// 获取host和port,细节不看
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
// 构造url。name是dubbo。所以构造的是dubbo协议的url。把map中的参数添加到url中。
//url如下: dubbo://192.168.106.1:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&bind.ip=192.168.106.1&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=30496®ister=true&release=2.7.2&side=provider×tamp=1635651181724
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
// 如果有协议对应的扩展配置工厂,会对url进行重写。默认没有
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
// 导出范围。有remote: 远程、local:jvm内部。默认两个都发布
String scope = url.getParameter(SCOPE_KEY);
// don't export when none is configured
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
// 导出本地不看
exportLocal(url);
}
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
...
// 前面都是写拼装url。registryURL是registry协议:registry://
// Invoker类是可适配扩展类,默认是javassistProxyFactory类:proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
// 这里构建invoker代理。传参:ref-真正实现类。interfaceClass-接口。还有一个url:url把registry协议的url和dubbo协议的url参数合并了。最终还是一个registry协议的url。
// Invoker类,有这三个变量的get方法。所以spi生成的适配器代理,会根据invoker.getUrl获取url,在根据url的动态参数调用指定实现类的方法。
// invoker类还有一个invoker。invoker方法可以可以看成普通的代理方法。调用包装的实现类的方法。
Invoker> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
// 对invoker和ServiceConfig再包一层
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// protocol是适配器扩展类。 protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
// 因为wrapperInvoker.getUrl.getProtocol获取的是registry。所以这里实际调用的RegistryProtocol的export方法
Exporter> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
接下来走到了RegistryProtocol的exprot方法。
@Override
public Exporter export(final Invoker originInvoker) throws RpcException {
// 获取registry协议的url。registry://
URL registryUrl = getRegistryUrl(originInvoker);
// url to export locally
// 获取dubbo协议的url。dubbo://
URL providerUrl = getProviderUrl(originInvoker);
// 下面url的订阅重写不看
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//export invoker
// 真正暴露服务,也就是暴露Invoker。originInvoker是封装了接口、接口实现类、url的invoker类,外面还包了一层的DelegateProviderMetaDataInvoker类。providerUrl是dubbo协议的url。
final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl);
// url to registry
final Registry registry = getRegistry(originInvoker);
final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
ProviderInvokerWrapper providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
registryUrl, registeredProviderUrl);
//to judge if we need to delay publish
boolean register = registeredProviderUrl.getParameter("register", true);
if (register) {
register(registryUrl, registeredProviderUrl);
providerInvokerWrapper.setReg(true);
}
// Deprecated! Subscribe to override rules in 2.6.x or before.
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter<>(exporter);
}
private ExporterChangeableWrapper doLocalExport(final Invoker originInvoker, URL providerUrl) {
// 从registry协议获取到的key是:dubbo://192.168.106.1:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&bind.ip=192.168.106.1&bind.port=20880&deprecated=false&dubbo=2.0.2&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=16556®ister=true&release=2.7.2&side=provider×tamp=1635736295334
String key = getCacheKey(originInvoker);
// bounds以key为url,value是ExporterChangeableWrapper的形式缓存了暴露的服务。
// computeIfAbsent方法就是说bounds没有就执行,执行的结果添加到bounds。
return (ExporterChangeableWrapper) bounds.computeIfAbsent(key, s -> {
// 又包了一层
Invoker> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
// protocol.export是真正暴露服务。暴露之后获取到Exporter类,然后和registry协议的invoker再封装成ExporterChangeableWrapper缓存起来。
// protocol是可适配扩展类。会根据invokerDelegate的url选择调用哪个实现类的方法。invokerDelegate的getUrl方法获取到的协议自然是dubbo协议。所以这里按道理是调用DubboProtocol的export方法。
// 但是其实这里还有个小细节。并非直接调用DubboProtocol的export方法,因为DubboProtocol在SPi加载的时候,外面包裹了三层Wrapper。具体往下看
return new ExporterChangeableWrapper<>((Exporter) protocol.export(invokerDelegate), originInvoker);
});
}
当ExtensionLoader.getExtension("dubbo")的时候,调用如下方法获取扩展类的时候。
private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class> clazz, String name) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
}
// 如果存在参数是class的构造方法,就说是Wrapper类,缓存起来。
else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
}
}
private T createExtension(String name) {
Class> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
// cachedWrapperClasses前面会缓存三个ProtocolFilterWrapper、ProtocolListenerWrapper、QosProtocolWrapper。
Set> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
// 这里会三个Wrapper一级一级包装
for (Class> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
有三个Wrapper类:ProtocolFilterWrapper、ProtocolListenerWrapper、QosProtocolWrapper。三个
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
public class ProtocolListenerWrapper implements Protocol {
private final Protocol protocol;
public ProtocolListenerWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
public class QosProtocolWrapper implements Protocol {
private final Logger logger = LoggerFactory.getLogger(QosProtocolWrapper.class);
private static AtomicBoolean hasStarted = new AtomicBoolean(false);
private Protocol protocol;
public QosProtocolWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
来到DubboProtocol的export方法
public Exporter export(Invoker invoker) throws RpcException {
// dubbo协议的url
URL url = invoker.getUrl();
// 从url中分析出可以:org.apache.dubbo.samples.api.GreetingsService:20880
String key = serviceKey(url);
// 封装一个exproter
DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
exporterMap.put(key, exporter);
// url中是否指明是回调服务和子事件。这里没有不管
Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice) {
String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
if (logger.isWarnEnabled()) {
logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
}
// 真正开启服务
openServer(url);
optimizeSerialization(url);
return exporter;
}
private void openServer(URL url) {
//key为192.168.106.1:20880,当前服务的地址和端口
String key = url.getAddress();
//client can export a service which's only for server to invoke
// 默认是是服务接口
boolean isServer = url.getParameter(IS_SERVER_KEY, true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
synchronized (this) {
server = serverMap.get(key);
if (server == null) {
// serverMap是Map,缓存了一下
serverMap.put(key, createServer(url));
}
}
} else {
// server supports reset, use together with override
server.reset(url);
}
}
}
private ExchangeServer createServer(URL url) {
// url添加一些参数。比如默认有心跳等
url = URLBuilder.from(url)
// send readonly event when server closes, it's enabled by default
.addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
// enable heartbeat by default
.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
.addParameter(CODEC_KEY, DubboCodec.NAME)
.build();
// DEFAULT_REMOTING_SERVER是netty。没有指定则默认是是netty服务
String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
}
ExchangeServer server;
try {
// dubbo专门封装了一个ExchangeServer来绑定url的服务
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
str = url.getParameter(CLIENT_KEY);
if (str != null && str.length() > 0) {
Set supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
// getExchange是适配器扩展,默认是HeaderExchange
return getExchanger(url).bind(url, handler);
}
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
// HeaderExchangeServer包裹了bind之后的Server对象,HeaderExchangeServer效果是能对Server对象进行健康检测好像
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handlers == null || handlers.length == 0) {
throw new IllegalArgumentException("handlers == null");
}
ChannelHandler handler;
if (handlers.length == 1) {
handler = handlers[0];
} else {
handler = new ChannelHandlerDispatcher(handlers);
}
// getTransporter获取适配器扩展,通过url参数动态调用实现类方法,这里默认是netty
return getTransporter().bind(url, handler);
}
public class NettyTransporter implements Transporter {
public static final String NAME = "netty";
@Override
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
后面就是正常的创建netty 服务了。就是熟悉的netty代码了。
public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}
@Override
protected void doOpen() throws Throwable {
bootstrap = new ServerBootstrap();
bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
new DefaultThreadFactory("NettyServerWorker", true));
final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
channels = nettyServerHandler.getChannels();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// FIXME: should we use getTimeout()?
int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
.addLast("decoder", adapter.getDecoder())
.addLast("encoder", adapter.getEncoder())
.addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS))
.addLast("handler", nettyServerHandler);
}
});
// bind
ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
channelFuture.syncUninterruptibly();
channel = channelFuture.channel();
}
看了服务导出代码,回过头来,看服务注册代码。RegistryProtocol的export方法
@Override
public Exporter export(final Invoker originInvoker) throws RpcException {
// 服务导出
final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl);
// 下面就是服务注册,这里获得的Zookeeper协议url:zookeeper://
// 自然这里获得的就是ZookeeperRegistry
final Registry registry = getRegistry(originInvoker);
// 如果registryUrl中有simplified参数,说明url需要精简,就会把providerUrl有关filter的参数都去掉,默认是要精简
final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
// 这里把invoker和url地址缓存了一下
ProviderInvokerWrapper providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
registryUrl, registeredProviderUrl);
//to judge if we need to delay publish
boolean register = registeredProviderUrl.getParameter("register", true);
if (register) {
// 这里真正注册。registryUrl是zookeeper://,registerProviderUrl是dubbo://
register(registryUrl, registeredProviderUrl);
providerInvokerWrapper.setReg(true);
}
// 订阅url重写,先不管
// Deprecated! Subscribe to override rules in 2.6.x or before.
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
// 注册之后,exporter set一下注册地址
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter<>(exporter);
}
private URL getRegistryUrl(Invoker> originInvoker) {
URL registryUrl = originInvoker.getUrl();
if (REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
// 因为registry协议url指定了registry参数是zookeeper,所以这里获得的协议就是zookeeper,如果没有指定就是dubbo协议 registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?...®istry=zookeeper&release=2.7.2×tamp=1635750787988
String protocol = registryUrl.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY);
registryUrl = registryUrl.setProtocol(protocol).removeParameter(REGISTRY_KEY);
}
return registryUrl;
}
public void register(URL registryUrl, URL registeredProviderUrl) {
// 可适配扩展,这里获得的自然是ZookeeperRegistry
Registry registry = registryFactory.getRegistry(registryUrl);
registry.register(registeredProviderUrl);
}
ZookeeperRegistry构造方法会建立跟zookeeper的连接。
@SPI("curator")
public interface ZookeeperTransporter {
@Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
ZookeeperClient connect(URL url);
}
// zookeeperTransporter是spi获取的,默认spi扩展类是curator
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
... 省略代码
// 建立连接
zkClient = zookeeperTransporter.connect(url);
zkClient.addStateListener(state -> {
if (state == StateListener.RECONNECTED) {
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
});
}
public class CuratorZookeeperTransporter extends AbstractZookeeperTransporter {
@Override
public ZookeeperClient createZookeeperClient(URL url) {
return new CuratorZookeeperClient(url);
}
zookeeperRegistry的registry方法调用的是父类FailbackRegistry,顾名思义,快速失败注册器
public void register(URL url) {
// 这里只是缓存添加了一份url
super.register(url);
// 下面两行代码,都是从failRegister中移除url,如果failRegister移除后不为空,则直接cancel取消。目的是当其他注册url失败了,则这里注册也马上取消,也就是快速失败的意思
removeFailedRegistered(url);
removeFailedUnregistered(url);
try {
// 这里真正注册。模板方法模式,子类ZookeeperRegistry调用。
doRegister(url);
} catch (Exception e) {
// 注册异常了,就添加到failRegister集合,用于前面的快速失败
// Record a failed registration request to a failed list, retry regularly
addFailedRegistered(url);
}
}
可以看到,zookeeper的注册,就是在zookeeper建立一个临时路径节点。
@Override
public void doRegister(URL url) {
try {
//zookeeper上创建的路径就是: /dubbo/org.apache.dubbo.samples.api.GreetingsService/providers/dubbo%3A%2F%2F192.168.106.1%3A20880%2Forg.apache.dubbo.samples.api.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.api.GreetingsService%26methods%3DsayHi%26pid%3D18400%26register%3Dtrue%26release%3D2.7.2%26side%3Dprovider%26timestamp%3D1635750787995
// 第二个参数,是否是创建的节点是临时的,默认是true:url.getParameter(DYNAMIC_KEY, true)
zkClient.create(toUrlPath(url),
);
} catch (Throwable e) {
throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
至此,导出和注册也就看完了。