diff --git a/pom.xml b/pom.xml
index 7576e14ee3..a55f97afc5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -206,6 +206,12 @@
true
+
+ io.netty
+ netty-resolver-dns
+ true
+
+
diff --git a/src/main/java/io/lettuce/core/AbstractRedisClient.java b/src/main/java/io/lettuce/core/AbstractRedisClient.java
index 599c4c2249..d6c908d1cc 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisClient.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisClient.java
@@ -73,6 +73,7 @@
* @author Mark Paluch
* @author Jongyeol Choi
* @author Poorva Gokhale
+ * @author Yohei Ueki
* @since 3.0
* @see ClientResources
*/
@@ -294,6 +295,15 @@ protected void channelType(ConnectionBuilder connectionBuilder, ConnectionPoint
}
}
+ protected void resolver(ConnectionBuilder connectionBuilder, ConnectionPoint connectionPoint) {
+
+ LettuceAssert.notNull(connectionPoint, "ConnectionPoint must not be null");
+
+ if (connectionPoint.getSocket() == null) {
+ connectionBuilder.bootstrap().resolver(clientResources.addressResolverGroup());
+ }
+ }
+
private EventLoopGroup getEventLoopGroup(Class extends EventLoopGroup> eventLoopGroupClass) {
for (;;) {
diff --git a/src/main/java/io/lettuce/core/RedisClient.java b/src/main/java/io/lettuce/core/RedisClient.java
index 76511ef79b..c501184396 100644
--- a/src/main/java/io/lettuce/core/RedisClient.java
+++ b/src/main/java/io/lettuce/core/RedisClient.java
@@ -75,6 +75,7 @@
*
* @author Will Glozer
* @author Mark Paluch
+ * @author Yohei Ueki
* @see RedisURI
* @see StatefulRedisConnection
* @see RedisFuture
diff --git a/src/main/java/io/lettuce/core/Transports.java b/src/main/java/io/lettuce/core/Transports.java
index 7ec977d30d..a29b8b1233 100644
--- a/src/main/java/io/lettuce/core/Transports.java
+++ b/src/main/java/io/lettuce/core/Transports.java
@@ -30,6 +30,8 @@
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.DatagramChannel;
+import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.internal.logging.InternalLogger;
@@ -40,9 +42,10 @@
* and domain socket transports.
*
* @author Mark Paluch
+ * @author Yohei Ueki
* @since 4.4
*/
-class Transports {
+public class Transports {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Transports.class);
@@ -61,7 +64,7 @@ static Class extends EventLoopGroup> eventLoopGroupClass() {
/**
* @return the default {@link Channel} for socket (network/TCP) transport.
*/
- static Class extends Channel> socketChannelClass() {
+ public static Class extends Channel> socketChannelClass() {
if (NativeTransports.isAvailable()) {
return NativeTransports.socketChannelClass();
@@ -70,6 +73,18 @@ static Class extends Channel> socketChannelClass() {
return NioSocketChannel.class;
}
+ /**
+ * @return the default {@link DatagramChannel} for socket (network/UDP) transport.
+ */
+ public static Class extends DatagramChannel> datagramChannelClass() {
+
+ if (NativeTransports.isSocketSupported()) {
+ return NativeTransports.datagramChannelClass();
+ }
+
+ return NioDatagramChannel.class;
+ }
+
/**
* Initialize the {@link Bootstrap} and apply {@link SocketOptions}.
*
@@ -146,6 +161,13 @@ static Class extends Channel> socketChannelClass() {
return RESOURCES.socketChannelClass();
}
+ /**
+ * @return the native transport socket {@link DatagramChannel} class.
+ */
+ static Class extends DatagramChannel> datagramChannelClass() {
+ return RESOURCES.datagramChannelClass();
+ }
+
/**
* @return the native transport domain socket {@link Channel} class.
*/
diff --git a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
index ce1a5d9039..cfd700e629 100644
--- a/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
+++ b/src/main/java/io/lettuce/core/cluster/RedisClusterClient.java
@@ -135,6 +135,7 @@
* possible.
*
* @author Mark Paluch
+ * @author Yohei Ueki
* @since 3.0
* @see RedisURI
* @see StatefulRedisClusterConnection
diff --git a/src/main/java/io/lettuce/core/resource/AddressResolverGroupProvider.java b/src/main/java/io/lettuce/core/resource/AddressResolverGroupProvider.java
new file mode 100644
index 0000000000..f0e663627b
--- /dev/null
+++ b/src/main/java/io/lettuce/core/resource/AddressResolverGroupProvider.java
@@ -0,0 +1,65 @@
+package io.lettuce.core.resource;
+
+import java.util.function.Supplier;
+
+import io.lettuce.core.Transports;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.resolver.AddressResolverGroup;
+import io.netty.resolver.DefaultAddressResolverGroup;
+import io.netty.resolver.dns.DnsAddressResolverGroup;
+import io.netty.resolver.dns.DnsNameResolverBuilder;
+import io.netty.util.internal.logging.InternalLogger;
+import io.netty.util.internal.logging.InternalLoggerFactory;
+
+/**
+ * Wraps and provides {@link AddressResolverGroup} classes. This is to protect the user from {@link ClassNotFoundException}'s
+ * caused by the absence of the {@literal netty-dns-resolver} library during runtime. This class will be deleted when
+ * {@literal netty-dns-resolver} becomes mandatory. Internal API.
+ *
+ * @author Yohei Ueki
+ * @since xxx
+ */
+class AddressResolverGroupProvider {
+
+ private static final InternalLogger logger = InternalLoggerFactory.getInstance(AddressResolverGroupProvider.class);
+
+ private static final AddressResolverGroup> ADDRESS_RESOLVER_GROUP;
+
+ static {
+ boolean dnsResolverAvailable;
+ try {
+ Class.forName("io.netty.resolver.dns.DnsAddressResolverGroup");
+ dnsResolverAvailable = true;
+ } catch (ClassNotFoundException e) {
+ dnsResolverAvailable = false;
+ }
+
+ // create addressResolverGroup instance via Supplier to avoid NoClassDefFoundError.
+ Supplier> supplier;
+ if (dnsResolverAvailable) {
+ logger.debug("Starting with netty's non-blocking DNS resolver library");
+ supplier = AddressResolverGroupProvider::defaultDnsAddressResolverGroup;
+ } else {
+ logger.debug("Starting without optional netty's non-blocking DNS resolver library");
+ supplier = () -> DefaultAddressResolverGroup.INSTANCE;
+ }
+ ADDRESS_RESOLVER_GROUP = supplier.get();
+ }
+
+ /**
+ * Returns the {@link AddressResolverGroup} for dns resolution.
+ *
+ * @return the {@link DnsAddressResolverGroup} if {@literal netty-dns-resolver} is available, otherwise return
+ * {@link DefaultAddressResolverGroup#INSTANCE}.
+ * @since xxx
+ */
+ static AddressResolverGroup> addressResolverGroup() {
+ return ADDRESS_RESOLVER_GROUP;
+ }
+
+ private static DnsAddressResolverGroup defaultDnsAddressResolverGroup() {
+ return new DnsAddressResolverGroup(new DnsNameResolverBuilder().channelType(Transports.datagramChannelClass())
+ .socketChannelType(Transports.socketChannelClass().asSubclass(SocketChannel.class)));
+ }
+
+}
diff --git a/src/main/java/io/lettuce/core/resource/ClientResources.java b/src/main/java/io/lettuce/core/resource/ClientResources.java
index 0029a99b93..9d834739da 100644
--- a/src/main/java/io/lettuce/core/resource/ClientResources.java
+++ b/src/main/java/io/lettuce/core/resource/ClientResources.java
@@ -24,6 +24,7 @@
import io.lettuce.core.metrics.CommandLatencyCollectorOptions;
import io.lettuce.core.metrics.CommandLatencyRecorder;
import io.lettuce.core.tracing.Tracing;
+import io.netty.resolver.AddressResolverGroup;
import io.netty.util.Timer;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.Future;
@@ -45,10 +46,12 @@
* {@link DnsResolver} to collect latency details. Requires the {@literal LatencyUtils} library.
* {@link Timer} for scheduling
* {@link Tracing} to trace Redis commands.
+ * {@link AddressResolverGroup} for dns resolution.
*
*
* @author Mark Paluch
* @author Mikhael Sokolov
+ * @author Yohei Ueki
* @since 3.4
* @see DefaultClientResources
*/
@@ -241,6 +244,18 @@ default Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCo
*/
Builder tracing(Tracing tracing);
+ /**
+ * Sets the {@link AddressResolverGroup} for dns resolution. This option is only effective if
+ * {@link DnsResolvers#UNRESOLVED} is used as {@link DnsResolver}. Defaults to
+ * {@link io.netty.resolver.DefaultAddressResolverGroup#INSTANCE} if {@literal netty-dns-resolver} is not available,
+ * otherwise defaults to {@link io.netty.resolver.dns.DnsAddressResolverGroup}.
+ *
+ * @param addressResolverGroup the {@link AddressResolverGroup} instance, must not be {@code null}.
+ * @return {@code this} {@link Builder}
+ * @since xxx
+ */
+ Builder addressResolverGroup(AddressResolverGroup> addressResolverGroup);
+
/**
* @return a new instance of {@link DefaultClientResources}.
*/
@@ -385,4 +400,12 @@ default Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCo
*/
Tracing tracing();
+ /**
+ * Return the {@link AddressResolverGroup} instance for dns resolution.
+ *
+ * @return the address resolver group.
+ * @since xxx
+ */
+ AddressResolverGroup> addressResolverGroup();
+
}
diff --git a/src/main/java/io/lettuce/core/resource/DefaultClientResources.java b/src/main/java/io/lettuce/core/resource/DefaultClientResources.java
index aff50dd992..71e5fa3860 100644
--- a/src/main/java/io/lettuce/core/resource/DefaultClientResources.java
+++ b/src/main/java/io/lettuce/core/resource/DefaultClientResources.java
@@ -35,6 +35,7 @@
import io.lettuce.core.metrics.MetricCollector;
import io.lettuce.core.resource.Delay.StatefulDelay;
import io.lettuce.core.tracing.Tracing;
+import io.netty.resolver.AddressResolverGroup;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
@@ -70,9 +71,11 @@
* a {@code socketAddressResolver} which is a provided instance of {@link SocketAddressResolver}.
* a {@code timer} that is a provided instance of {@link io.netty.util.HashedWheelTimer}.
* a {@code tracing} that is a provided instance of {@link Tracing}.
+ * a {@code addressResolverGroup} that is a provided instance of {@link AddressResolverGroup}.
*
*
* @author Mark Paluch
+ * @author Yohei Ueki
* @since 3.4
*/
public class DefaultClientResources implements ClientResources {
@@ -103,6 +106,12 @@ public class DefaultClientResources implements ClientResources {
*/
public static final NettyCustomizer DEFAULT_NETTY_CUSTOMIZER = DefaultNettyCustomizer.INSTANCE;
+ /**
+ * Default {@link AddressResolverGroup}.
+ */
+ public static final AddressResolverGroup> DEFAULT_ADDRESS_RESOLVER_GROUP = AddressResolverGroupProvider
+ .addressResolverGroup();
+
static {
int threads = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads",
@@ -147,6 +156,8 @@ public class DefaultClientResources implements ClientResources {
private final Tracing tracing;
+ private final AddressResolverGroup> addressResolverGroup;
+
private volatile boolean shutdownCalled = false;
protected DefaultClientResources(Builder builder) {
@@ -243,6 +254,7 @@ protected DefaultClientResources(Builder builder) {
reconnectDelay = builder.reconnectDelay;
nettyCustomizer = builder.nettyCustomizer;
tracing = builder.tracing;
+ addressResolverGroup = builder.addressResolverGroup;
if (!sharedTimer && timer instanceof HashedWheelTimer) {
((HashedWheelTimer) timer).start();
@@ -308,6 +320,8 @@ public static class Builder implements ClientResources.Builder {
private Tracing tracing = Tracing.disabled();
+ private AddressResolverGroup> addressResolverGroup = DEFAULT_ADDRESS_RESOLVER_GROUP;
+
private Builder() {
}
@@ -569,6 +583,25 @@ public Builder tracing(Tracing tracing) {
return this;
}
+ /**
+ * Sets the {@link AddressResolverGroup} for dns resolution. This option is only effective if
+ * {@link DnsResolvers#UNRESOLVED} is used as {@link DnsResolver}. Defaults to
+ * {@link io.netty.resolver.DefaultAddressResolverGroup#INSTANCE} if {@literal netty-dns-resolver} is not available,
+ * otherwise defaults to {@link io.netty.resolver.dns.DnsAddressResolverGroup}.
+ *
+ * @param addressResolverGroup the {@link AddressResolverGroup} instance, must not be {@code null}.
+ * @return {@code this} {@link ClientResources.Builder}
+ * @since xxx
+ */
+ @Override
+ public Builder addressResolverGroup(AddressResolverGroup> addressResolverGroup) {
+
+ LettuceAssert.notNull(addressResolverGroup, "AddressResolverGroup must not be null");
+
+ this.addressResolverGroup = addressResolverGroup;
+ return this;
+ }
+
/**
* @return a new instance of {@link DefaultClientResources}.
*/
@@ -603,7 +636,7 @@ public DefaultClientResources.Builder mutate() {
.commandLatencyPublisherOptions(commandLatencyPublisherOptions()).dnsResolver(dnsResolver())
.eventBus(eventBus()).eventExecutorGroup(eventExecutorGroup()).reconnectDelay(reconnectDelay)
.socketAddressResolver(socketAddressResolver()).nettyCustomizer(nettyCustomizer()).timer(timer())
- .tracing(tracing());
+ .tracing(tracing()).addressResolverGroup(addressResolverGroup());
builder.sharedCommandLatencyCollector = sharedEventLoopGroupProvider;
builder.sharedEventExecutor = sharedEventExecutor;
@@ -742,4 +775,9 @@ public Tracing tracing() {
return tracing;
}
+ @Override
+ public AddressResolverGroup> addressResolverGroup() {
+ return addressResolverGroup;
+ }
+
}
diff --git a/src/main/java/io/lettuce/core/resource/EpollProvider.java b/src/main/java/io/lettuce/core/resource/EpollProvider.java
index 158a160bea..a995afbfec 100644
--- a/src/main/java/io/lettuce/core/resource/EpollProvider.java
+++ b/src/main/java/io/lettuce/core/resource/EpollProvider.java
@@ -25,9 +25,11 @@
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollChannelOption;
+import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollDomainSocketChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollSocketChannel;
+import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.internal.SystemPropertyUtil;
@@ -39,6 +41,7 @@
* the {@literal netty-transport-native-epoll} library during runtime. Internal API.
*
* @author Mark Paluch
+ * @author Yohei Ueki
* @since 4.4
*/
public class EpollProvider {
@@ -168,6 +171,13 @@ public SocketAddress newSocketAddress(String socketPath) {
return null;
}
+ @Override
+ public Class extends DatagramChannel> datagramChannelClass() {
+
+ checkForEpollLibrary();
+ return null;
+ }
+
}
/**
@@ -209,6 +219,14 @@ public Class extends Channel> socketChannelClass() {
return EpollSocketChannel.class;
}
+ @Override
+ public Class extends DatagramChannel> datagramChannelClass() {
+
+ checkForEpollLibrary();
+
+ return EpollDatagramChannel.class;
+ }
+
@Override
public Class extends Channel> domainSocketChannelClass() {
diff --git a/src/main/java/io/lettuce/core/resource/EventLoopResources.java b/src/main/java/io/lettuce/core/resource/EventLoopResources.java
index 17b5365622..e9c3db0193 100644
--- a/src/main/java/io/lettuce/core/resource/EventLoopResources.java
+++ b/src/main/java/io/lettuce/core/resource/EventLoopResources.java
@@ -21,12 +21,14 @@
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.socket.DatagramChannel;
import io.netty.util.concurrent.EventExecutorGroup;
/**
* Interface to encapsulate EventLoopGroup resources.
*
* @author Mark Paluch
+ * @author Yohei Ueki
* @since 6.0
*/
public interface EventLoopResources {
@@ -58,6 +60,11 @@ public interface EventLoopResources {
*/
Class extends Channel> socketChannelClass();
+ /**
+ * @return the {@link DatagramChannel} class.
+ */
+ Class extends DatagramChannel> datagramChannelClass();
+
/**
* @return the Domain Socket {@link Channel} class.
*/
diff --git a/src/main/java/io/lettuce/core/resource/KqueueProvider.java b/src/main/java/io/lettuce/core/resource/KqueueProvider.java
index b8580212d0..20aebdee58 100644
--- a/src/main/java/io/lettuce/core/resource/KqueueProvider.java
+++ b/src/main/java/io/lettuce/core/resource/KqueueProvider.java
@@ -22,9 +22,11 @@
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.kqueue.KQueue;
+import io.netty.channel.kqueue.KQueueDatagramChannel;
import io.netty.channel.kqueue.KQueueDomainSocketChannel;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.kqueue.KQueueSocketChannel;
+import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.internal.SystemPropertyUtil;
@@ -36,6 +38,7 @@
* the {@literal netty-transport-native-kqueue} library during runtime. Internal API.
*
* @author Mark Paluch
+ * @author Yohei Ueki
* @since 4.4
*/
public class KqueueProvider {
@@ -153,6 +156,15 @@ public SocketAddress newSocketAddress(String socketPath) {
return null;
}
+ @Override
+ public Class extends DatagramChannel> datagramChannelClass() {
+
+
+ checkForKqueueLibrary();
+ return null;
+ }
+
+
}
/**
@@ -194,6 +206,15 @@ public Class extends Channel> socketChannelClass() {
return KQueueSocketChannel.class;
}
+ @Override
+ public Class extends DatagramChannel> datagramChannelClass() {
+
+ checkForKqueueLibrary();
+
+ return KQueueDatagramChannel.class;
+ }
+
+
@Override
public Class extends Channel> domainSocketChannelClass() {
diff --git a/src/test/java/io/lettuce/core/resource/DefaultClientResourcesUnitTests.java b/src/test/java/io/lettuce/core/resource/DefaultClientResourcesUnitTests.java
index e98f53cc55..0eb49f02cd 100644
--- a/src/test/java/io/lettuce/core/resource/DefaultClientResourcesUnitTests.java
+++ b/src/test/java/io/lettuce/core/resource/DefaultClientResourcesUnitTests.java
@@ -30,6 +30,7 @@
import io.lettuce.test.TestFutures;
import io.lettuce.test.resource.FastShutdown;
import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.resolver.AddressResolverGroup;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import io.netty.util.concurrent.EventExecutorGroup;
@@ -39,6 +40,7 @@
* Unit tests for {@link DefaultClientResources}.
*
* @author Mark Paluch
+ * @author Yohei Ueki
*/
class DefaultClientResourcesUnitTests {
@@ -108,16 +110,19 @@ void testProvidedResources() {
EventBus eventBusMock = mock(EventBus.class);
CommandLatencyCollector latencyCollectorMock = mock(CommandLatencyCollector.class);
NettyCustomizer nettyCustomizer = mock(NettyCustomizer.class);
+ AddressResolverGroup> addressResolverGroup = mock(AddressResolverGroup.class);
DefaultClientResources sut = DefaultClientResources.builder().eventExecutorGroup(executorMock)
.eventLoopGroupProvider(groupProviderMock).timer(timerMock).eventBus(eventBusMock)
- .commandLatencyRecorder(latencyCollectorMock).nettyCustomizer(nettyCustomizer).build();
+ .commandLatencyRecorder(latencyCollectorMock).nettyCustomizer(nettyCustomizer)
+ .addressResolverGroup(addressResolverGroup).build();
assertThat(sut.eventExecutorGroup()).isSameAs(executorMock);
assertThat(sut.eventLoopGroupProvider()).isSameAs(groupProviderMock);
assertThat(sut.timer()).isSameAs(timerMock);
assertThat(sut.eventBus()).isSameAs(eventBusMock);
assertThat(sut.nettyCustomizer()).isSameAs(nettyCustomizer);
+ assertThat(sut.addressResolverGroup()).isSameAs(addressResolverGroup);
assertThat(TestFutures.getOrTimeout(sut.shutdown())).isTrue();
@@ -137,11 +142,11 @@ void mutateResources() {
Timer timerMock2 = mock(Timer.class);
EventBus eventBusMock = mock(EventBus.class);
CommandLatencyCollector latencyCollectorMock = mock(CommandLatencyCollector.class);
-
+ AddressResolverGroup> addressResolverGroupMock = mock(AddressResolverGroup.class);
ClientResources sut = ClientResources.builder().eventExecutorGroup(executorMock)
.eventLoopGroupProvider(groupProviderMock).timer(timerMock).eventBus(eventBusMock)
- .commandLatencyRecorder(latencyCollectorMock).build();
+ .commandLatencyRecorder(latencyCollectorMock).addressResolverGroup(addressResolverGroupMock).build();
ClientResources copy = sut.mutate().timer(timerMock2).build();
@@ -151,6 +156,7 @@ void mutateResources() {
assertThat(sut.timer()).isSameAs(timerMock);
assertThat(copy.timer()).isSameAs(timerMock2).isNotSameAs(timerMock);
assertThat(sut.eventBus()).isSameAs(eventBusMock);
+ assertThat(sut.addressResolverGroup()).isSameAs(addressResolverGroupMock);
assertThat(TestFutures.getOrTimeout(sut.shutdown())).isTrue();
diff --git a/src/test/jmh/io/lettuce/core/protocol/EmptyClientResources.java b/src/test/jmh/io/lettuce/core/protocol/EmptyClientResources.java
index 82a5373d8d..d38d2bd42b 100644
--- a/src/test/jmh/io/lettuce/core/protocol/EmptyClientResources.java
+++ b/src/test/jmh/io/lettuce/core/protocol/EmptyClientResources.java
@@ -28,6 +28,7 @@
import io.lettuce.core.metrics.CommandMetrics;
import io.lettuce.core.resource.*;
import io.lettuce.core.tracing.Tracing;
+import io.netty.resolver.AddressResolverGroup;
import io.netty.util.Timer;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.Future;
@@ -36,6 +37,7 @@
/**
* @author Mark Paluch
+ * @author Yohei Ueki
*/
public class EmptyClientResources implements ClientResources {
@@ -123,6 +125,11 @@ public Tracing tracing() {
return Tracing.disabled();
}
+ @Override
+ public AddressResolverGroup> addressResolverGroup() {
+ return null;
+ }
+
public static class EmptyCommandLatencyCollector implements CommandLatencyCollector {
@Override