Use bean class loader when detecting ClientHttpRequestFactoryBuilder
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run
Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions
Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[early-access:true toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[early-access:true toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:22], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:22], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run
Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run
Details
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run
Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions
Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[early-access:true toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[early-access:true toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:22], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:22], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:windows-latest name:Windows]) (push) Waiting to run
Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run
Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run
Details
Update `ClientHttpRequestFactoryBuilder` with a detect method that accepts a specific classloader and update `HttpClientAutoConfiguration` to use it. Fixes gh-44986
This commit is contained in:
parent
95325a87ba
commit
417a4a0386
|
@ -48,11 +48,12 @@ public abstract class AbstractHttpRequestFactoryProperties extends AbstractHttpC
|
|||
|
||||
/**
|
||||
* Return a {@link ClientHttpRequestFactoryBuilder} based on the properties.
|
||||
* @param classLoader the class loader to use for detection
|
||||
* @return a {@link ClientHttpRequestFactoryBuilder}
|
||||
*/
|
||||
protected final ClientHttpRequestFactoryBuilder<?> factoryBuilder() {
|
||||
protected final ClientHttpRequestFactoryBuilder<?> factoryBuilder(ClassLoader classLoader) {
|
||||
Factory factory = getFactory();
|
||||
return (factory != null) ? factory.builder() : ClientHttpRequestFactoryBuilder.detect();
|
||||
return (factory != null) ? factory.builder() : ClientHttpRequestFactoryBuilder.detect(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.http.client;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
@ -47,13 +48,20 @@ import org.springframework.http.client.ClientHttpRequestFactory;
|
|||
@ConditionalOnClass(ClientHttpRequestFactory.class)
|
||||
@Conditional(NotReactiveWebApplicationCondition.class)
|
||||
@EnableConfigurationProperties(HttpClientProperties.class)
|
||||
public class HttpClientAutoConfiguration {
|
||||
public class HttpClientAutoConfiguration implements BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(HttpClientProperties httpClientProperties,
|
||||
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
|
||||
ClientHttpRequestFactoryBuilder<?> builder = httpClientProperties.factoryBuilder();
|
||||
ClientHttpRequestFactoryBuilder<?> builder = httpClientProperties.factoryBuilder(this.beanClassLoader);
|
||||
return customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,11 @@ import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
|
|||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
|
||||
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
|
||||
import org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.JettyClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.ReactorClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -87,6 +90,32 @@ class HttpClientAutoConfigurationTests {
|
|||
return propertyValues;
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenHttpComponentsIsUnavailableThenJettyClientBeansAreDefined() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(org.apache.hc.client5.http.impl.classic.HttpClients.class))
|
||||
.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))
|
||||
.isExactlyInstanceOf(JettyClientHttpRequestFactoryBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenHttpComponentsAndJettyAreUnavailableThenReactorClientBeansAreDefined() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(org.apache.hc.client5.http.impl.classic.HttpClients.class,
|
||||
org.eclipse.jetty.client.HttpClient.class))
|
||||
.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))
|
||||
.isExactlyInstanceOf(ReactorClientHttpRequestFactoryBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenHttpComponentsAndJettyAndReactorAreUnavailableThenJdkClientBeansAreDefined() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(org.apache.hc.client5.http.impl.classic.HttpClients.class,
|
||||
org.eclipse.jetty.client.HttpClient.class, reactor.netty.http.client.HttpClient.class))
|
||||
.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))
|
||||
.isExactlyInstanceOf(JdkClientHttpRequestFactoryBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReactiveWebApplicationBeansAreNotConfigured() {
|
||||
new ReactiveWebApplicationContextRunner().withConfiguration(autoConfigurations)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -196,16 +196,34 @@ public interface ClientHttpRequestFactoryBuilder<T extends ClientHttpRequestFact
|
|||
* @return the most suitable {@link ClientHttpRequestFactoryBuilder} for the classpath
|
||||
*/
|
||||
static ClientHttpRequestFactoryBuilder<? extends ClientHttpRequestFactory> detect() {
|
||||
if (HttpComponentsClientHttpRequestFactoryBuilder.Classes.PRESENT) {
|
||||
return detect(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the most suitable {@link ClientHttpRequestFactoryBuilder} based on the
|
||||
* classpath. The methods favors builders in the following order:
|
||||
* <ol>
|
||||
* <li>{@link #httpComponents()}</li>
|
||||
* <li>{@link #jetty()}</li>
|
||||
* <li>{@link #reactor()}</li>
|
||||
* <li>{@link #jdk()}</li>
|
||||
* <li>{@link #simple()}</li>
|
||||
* </ol>
|
||||
* @param classLoader the class loader to use for detection
|
||||
* @return the most suitable {@link ClientHttpRequestFactoryBuilder} for the classpath
|
||||
* @since 3.5.0
|
||||
*/
|
||||
static ClientHttpRequestFactoryBuilder<? extends ClientHttpRequestFactory> detect(ClassLoader classLoader) {
|
||||
if (HttpComponentsClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {
|
||||
return httpComponents();
|
||||
}
|
||||
if (JettyClientHttpRequestFactoryBuilder.Classes.PRESENT) {
|
||||
if (JettyClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {
|
||||
return jetty();
|
||||
}
|
||||
if (ReactorClientHttpRequestFactoryBuilder.Classes.PRESENT) {
|
||||
if (ReactorClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {
|
||||
return reactor();
|
||||
}
|
||||
if (JdkClientHttpRequestFactoryBuilder.Classes.PRESENT) {
|
||||
if (JdkClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {
|
||||
return jdk();
|
||||
}
|
||||
return simple();
|
||||
|
|
|
@ -156,7 +156,9 @@ public final class HttpComponentsClientHttpRequestFactoryBuilder
|
|||
|
||||
static final String HTTP_CLIENTS = "org.apache.hc.client5.http.impl.classic.HttpClients";
|
||||
|
||||
static final boolean PRESENT = ClassUtils.isPresent(HTTP_CLIENTS, null);
|
||||
static boolean present(ClassLoader classLoader) {
|
||||
return ClassUtils.isPresent(HTTP_CLIENTS, classLoader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,9 @@ public final class JdkClientHttpRequestFactoryBuilder
|
|||
|
||||
static final String HTTP_CLIENT = "java.net.http.HttpClient";
|
||||
|
||||
static final boolean PRESENT = ClassUtils.isPresent(HTTP_CLIENT, null);
|
||||
static boolean present(ClassLoader classLoader) {
|
||||
return ClassUtils.isPresent(HTTP_CLIENT, classLoader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,9 @@ public final class JettyClientHttpRequestFactoryBuilder
|
|||
|
||||
static final String HTTP_CLIENT = "org.eclipse.jetty.client.HttpClient";
|
||||
|
||||
static final boolean PRESENT = ClassUtils.isPresent(HTTP_CLIENT, null);
|
||||
static boolean present(ClassLoader classLoader) {
|
||||
return ClassUtils.isPresent(HTTP_CLIENT, classLoader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,9 @@ public final class ReactorClientHttpRequestFactoryBuilder
|
|||
|
||||
static final String HTTP_CLIENT = "reactor.netty.http.client.HttpClient";
|
||||
|
||||
static final boolean PRESENT = ClassUtils.isPresent(HTTP_CLIENT, null);
|
||||
static boolean present(ClassLoader classLoader) {
|
||||
return ClassUtils.isPresent(HTTP_CLIENT, classLoader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue