The logic right now is like this:

public ReactorClientHttpConnector(ReactorResourceFactory factory, Function<HttpClient, HttpClient> mapper) {
        this.httpClient = defaultInitializer.andThen(mapper).apply(initHttpClient(factory));
}

@SuppressWarnings("deprecation")
private static HttpClient initHttpClient(ReactorResourceFactory resourceFactory) {
    ConnectionProvider provider = resourceFactory.getConnectionProvider();
    LoopResources resources = resourceFactory.getLoopResources();
    Assert.notNull(provider, "No ConnectionProvider: is ReactorResourceFactory not initialized yet?");
    Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?");
    return HttpClient.create(provider).tcpConfiguration(tcpClient -> tcpClient.runOn(resources));
}

And that mapper is called when tcpConfiguration() has done its logic.

In the native image on Windows it fails like:

Caused by: java.lang.ExceptionInInitializerError
    at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder$1.provider(DnsServerAddressStreamProviders.java:140)
    at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder$1.<init>(DnsServerAddressStreamProviders.java:120)
    at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder.<clinit>(DnsServerAddressStreamProviders.java:118)
    at io.netty.resolver.dns.DnsServerAddressStreamProviders.unixDefault(DnsServerAddressStreamProviders.java:107)
    at io.netty.resolver.dns.DnsServerAddressStreamProviders.platformDefault(DnsServerAddressStreamProviders.java:103)
    at io.netty.resolver.dns.DnsNameResolverBuilder.<init>(DnsNameResolverBuilder.java:60)
    at reactor.netty.transport.NameResolverProvider.newNameResolverGroup(NameResolverProvider.java:455)
    at reactor.netty.transport.ClientTransportConfig.lambda$getOrCreateResolver$0(ClientTransportConfig.java:239)
    at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1705)
    at reactor.netty.transport.ClientTransportConfig.getOrCreateResolver(ClientTransportConfig.java:238)
    at reactor.netty.transport.ClientTransport.runOn(ClientTransport.java:352)
    at reactor.netty.transport.ClientTransport.runOn(ClientTransport.java:42)
    at reactor.netty.transport.Transport.runOn(Transport.java:249)
    at reactor.netty.http.client.HttpClientTcpConfig.runOn(HttpClientTcpConfig.java:189)
    at org.springframework.http.client.reactive.ReactorClientHttpConnector.lambda$initHttpClient$1(ReactorClientHttpConnector.java:85)
    at reactor.netty.http.client.HttpClient.tcpConfiguration(HttpClient.java:1494)
    at org.springframework.http.client.reactive.ReactorClientHttpConnector.initHttpClient(ReactorClientHttpConnector.java:85)
    at org.springframework.http.client.reactive.ReactorClientHttpConnector.<init>(ReactorClientHttpConnector.java:76)
    at org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorConfiguration$ReactorNetty.reactorClientHttpConnector(ClientHttpConnectorConfiguration.java:66)
    at org.springframework.boot.autoconfigure.web.reactive.function.client.ContextBootstrapInitializer.lambda$registerReactorNetty_reactorClientHttpConnector$0(ContextBootstrapInitializer.java:19)
    at org.springframework.aot.beans.factory.ThrowableFunction.apply(ThrowableFunction.java:18)
    at org.springframework.aot.beans.factory.InjectedElementResolver.create(InjectedElementResolver.java:51)
    at org.springframework.aot.beans.factory.BeanDefinitionRegistrar$InstanceSupplierContext.create(BeanDefinitionRegistrar.java:193)
    at org.springframework.boot.autoconfigure.web.reactive.function.client.ContextBootstrapInitializer.lambda$registerReactorNetty_reactorClientHttpConnector$1(ContextBootstrapInitializer.java:19)
    at org.springframework.aot.beans.factory.ThrowableFunction.apply(ThrowableFunction.java:18)
    at org.springframework.aot.beans.factory.BeanDefinitionRegistrar.lambda$instanceSupplier$0(BeanDefinitionRegistrar.java:97)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1249)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    ... 52 more
Caused by: java.lang.NullPointerException
    at java.util.StringTokenizer.<init>(StringTokenizer.java:199)
    at java.util.StringTokenizer.<init>(StringTokenizer.java:221)
    at sun.net.dns.ResolverConfigurationImpl.stringToList(ResolverConfigurationImpl.java:69)
    at sun.net.dns.ResolverConfigurationImpl.loadConfig(ResolverConfigurationImpl.java:104)
    at sun.net.dns.ResolverConfigurationImpl.nameservers(ResolverConfigurationImpl.java:127)
    at com.sun.jndi.dns.DnsContextFactory.serversForUrls(DnsContextFactory.java:149)
    at com.sun.jndi.dns.DnsContextFactory.getContext(DnsContextFactory.java:81)
    at com.sun.jndi.dns.DnsContextFactory.urlToContext(DnsContextFactory.java:120)
    at com.sun.jndi.dns.DnsContextFactory.getInitialContext(DnsContextFactory.java:64)
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:730)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
    at javax.naming.InitialContext.init(InitialContext.java:236)
    at javax.naming.InitialContext.<init>(InitialContext.java:208)
    at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101)
    at io.netty.resolver.dns.DirContextUtils.addNameServers(DirContextUtils.java:49)
    at io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.<clinit>(DefaultDnsServerAddressStreamProvider.java:53)
    ... 82 more

Even if I provide this customizer:

    @Bean
    ReactorNettyHttpClientMapper reactorNettyHttpClientMapper() {
        return httpClient -> httpClient.resolver(DefaultAddressResolverGroup.INSTANCE);
    }

In my opinion it has to be like this:

HttpClient httpClient =
                mapper.apply(HttpClient.create(provider))
                .tcpConfiguration(tcpClient -> tcpClient.runOn(resources));

This one works for me in my Spring Boot application:

    @Bean
    ReactorResourceFactory reactorClientResourceFactory() {
        return new ReactorResourceFactory();
    }

    @Bean
    ReactorClientHttpConnector reactorClientHttpConnector(ReactorResourceFactory reactorResourceFactory) {
        ConnectionProvider provider = reactorResourceFactory.getConnectionProvider();
        LoopResources resources = reactorResourceFactory.getLoopResources();
        Function<HttpClient, HttpClient> mapper =
                httpClient -> httpClient.resolver(DefaultAddressResolverGroup.INSTANCE);
        HttpClient httpClient =
                mapper.apply(HttpClient.create(provider))
                        .tcpConfiguration(tcpClient -> tcpClient.runOn(resources));

        return new ReactorClientHttpConnector(httpClient);
    }

See more info in this Reactor Netty issue: https://github.com/reactor/reactor-netty/issues/1431

Comment From: rstoyanchev

Given that ResourceFactory is passed in, clearly the intent is to apply it. I think it's okay to move it and have it applied after the provided mapper. The two shouldn't be competing with each other.