Browse Source

Merge branch '3.5.x'

Closes gh-47751
pull/47284/head
Phillip Webb 3 months ago
parent
commit
350179901f
  1. 11
      buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java
  2. 9
      buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java
  3. 82
      buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java
  4. 36
      buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestConditionalOnClass.java
  5. 30
      buildSrc/src/test/java/org/springframework/boot/build/architecture/conditionalonclass/OnBeanMethod.java
  6. 2
      documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/test-modules.adoc
  7. 30
      module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java
  8. 52
      module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayAutoConfiguration.java
  9. 2
      module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesAutoConfigurationTests.java
  10. 20
      module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java
  11. 1
      module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/SecurityRequestMatchersManagementContextConfiguration.java
  12. 34
      module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinAutoConfiguration.java

11
buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java

@ -72,15 +72,19 @@ import org.gradle.api.tasks.VerificationException; @@ -72,15 +72,19 @@ import org.gradle.api.tasks.VerificationException;
*/
public abstract class ArchitectureCheck extends DefaultTask {
private static final String CONDITIONAL_ON_CLASS_ANNOTATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnClass";
private FileCollection classes;
public ArchitectureCheck() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
getConditionalOnClassAnnotation().convention(CONDITIONAL_ON_CLASS_ANNOTATION);
getRules().addAll(getProhibitObjectsRequireNonNull().convention(true)
.map(whenTrue(ArchitectureRules::noClassesShouldCallObjectsRequireNonNull)));
getRules().addAll(ArchitectureRules.standard());
getRules().addAll(whenMainSources(
() -> Collections.singletonList(ArchitectureRules.allBeanMethodsShouldReturnNonPrivateType())));
getRules().addAll(whenMainSources(() -> List
.of(ArchitectureRules.allBeanMethodsShouldReturnNonPrivateType(), ArchitectureRules
.allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(getConditionalOnClassAnnotation().get()))));
getRules().addAll(and(getNullMarkedEnabled(), isMainSourceSet()).map(whenTrue(() -> Collections.singletonList(
ArchitectureRules.packagesShouldBeAnnotatedWithNullMarked(getNullMarkedIgnoredPackages().get())))));
getRuleDescriptions().set(getRules().map(this::asDescriptions));
@ -205,4 +209,7 @@ public abstract class ArchitectureCheck extends DefaultTask { @@ -205,4 +209,7 @@ public abstract class ArchitectureCheck extends DefaultTask {
@Internal
abstract SetProperty<String> getNullMarkedIgnoredPackages();
@Internal
abstract Property<String> getConditionalOnClassAnnotation();
}

9
buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java

@ -130,6 +130,15 @@ final class ArchitectureRules { @@ -130,6 +130,15 @@ final class ArchitectureRules {
.allowEmptyShould(true);
}
static ArchRule allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(String annotationName) {
return methodsThatAreAnnotatedWith("org.springframework.context.annotation.Bean").should()
.notBeAnnotatedWith(annotationName)
.because("@ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent "
+ "the method signature from being loaded. Such condition need to be placed"
+ " on a @Configuration class, allowing the condition to back off before the type is loaded.")
.allowEmptyShould(true);
}
private static ArchRule allPackagesShouldBeFreeOfTangles() {
return SlicesRuleDefinition.slices()
.matching("(**)")

82
buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java

@ -41,6 +41,7 @@ import org.junit.jupiter.api.io.TempDir; @@ -41,6 +41,7 @@ import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileSystemUtils;
@ -183,7 +184,7 @@ class ArchitectureCheckTests { @@ -183,7 +184,7 @@ class ArchitectureCheckTests {
void whenClassCallsObjectsRequireNonNullWithMessageAndProhibitObjectsRequireNonNullIsFalseShouldSucceedAndWriteEmptyReport(
Task task) throws IOException {
prepareTask(task, "objects/requireNonNullWithString");
build(this.gradleBuild.withProhibitObjectsRequireNonNull(task, false), task);
build(this.gradleBuild.withProhibitObjectsRequireNonNull(false), task);
}
@ParameterizedTest(name = "{0}")
@ -198,7 +199,7 @@ class ArchitectureCheckTests { @@ -198,7 +199,7 @@ class ArchitectureCheckTests {
void whenClassCallsObjectsRequireNonNullWithSupplierAndProhibitObjectsRequireNonNullIsFalseShouldSucceedAndWriteEmptyReport(
Task task) throws IOException {
prepareTask(task, "objects/requireNonNullWithSupplier");
build(this.gradleBuild.withProhibitObjectsRequireNonNull(task, false), task);
build(this.gradleBuild.withProhibitObjectsRequireNonNull(false), task);
}
@ParameterizedTest(name = "{0}")
@ -320,6 +321,25 @@ class ArchitectureCheckTests { @@ -320,6 +321,25 @@ class ArchitectureCheckTests {
"should not have a value that is the same as the type of the method's first parameter");
}
@Test
void whenConditionalOnClassUsedOnBeanMethodsWithMainSourcesShouldFailAndWriteReport() throws IOException {
prepareTask(Task.CHECK_ARCHITECTURE_MAIN, "conditionalonclass", "annotations");
GradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT)
.withConditionalOnClassAnnotation(TestConditionalOnClass.class.getName());
buildAndFail(gradleBuild, Task.CHECK_ARCHITECTURE_MAIN,
"because @ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent"
+ " the method signature from being loaded. Such condition need to be placed"
+ " on a @Configuration class, allowing the condition to back off before the type is loaded");
}
@Test
void whenConditionalOnClassUsedOnBeanMethodsWithTestSourcesShouldSucceedAndWriteEmptyReport() throws IOException {
prepareTask(Task.CHECK_ARCHITECTURE_TEST, "conditionalonclass", "annotations");
GradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT)
.withConditionalOnClassAnnotation(TestConditionalOnClass.class.getName());
build(gradleBuild, Task.CHECK_ARCHITECTURE_TEST);
}
private void prepareTask(Task task, String... sourceDirectories) throws IOException {
for (String sourceDirectory : sourceDirectories) {
FileSystemUtils.copyRecursively(
@ -335,7 +355,7 @@ class ArchitectureCheckTests { @@ -335,7 +355,7 @@ class ArchitectureCheckTests {
private void build(GradleBuild gradleBuild, Task task) throws IOException {
try {
BuildResult buildResult = gradleBuild.build(task.toString());
assertThat(buildResult.taskPaths(TaskOutcome.SUCCESS)).contains(":" + task);
assertThat(buildResult.taskPaths(TaskOutcome.SUCCESS)).as(buildResult.getOutput()).contains(":" + task);
assertThat(task.getFailureReport(gradleBuild.getProjectDir())).isEmpty();
}
catch (UnexpectedBuildFailure ex) {
@ -351,7 +371,7 @@ class ArchitectureCheckTests { @@ -351,7 +371,7 @@ class ArchitectureCheckTests {
private void buildAndFail(GradleBuild gradleBuild, Task task, String... messages) throws IOException {
try {
BuildResult buildResult = gradleBuild.buildAndFail(task.toString());
assertThat(buildResult.taskPaths(TaskOutcome.FAILED)).contains(":" + task);
assertThat(buildResult.taskPaths(TaskOutcome.FAILED)).as(buildResult.getOutput()).contains(":" + task);
assertThat(task.getFailureReport(gradleBuild.getProjectDir())).contains(messages);
}
catch (UnexpectedBuildSuccess ex) {
@ -396,10 +416,10 @@ class ArchitectureCheckTests { @@ -396,10 +416,10 @@ class ArchitectureCheckTests {
private final Set<String> dependencies = new LinkedHashSet<>();
private final Map<Task, Boolean> prohibitObjectsRequireNonNull = new LinkedHashMap<>();
private NullMarkedExtension nullMarkedExtension;
private final Map<Task, TaskConfiguration> taskConfigurations = new LinkedHashMap<>();
private GradleBuild(Path projectDir) {
this.projectDir = projectDir;
}
@ -408,8 +428,18 @@ class ArchitectureCheckTests { @@ -408,8 +428,18 @@ class ArchitectureCheckTests {
return this.projectDir;
}
GradleBuild withProhibitObjectsRequireNonNull(Task task, boolean prohibitObjectsRequireNonNull) {
this.prohibitObjectsRequireNonNull.put(task, prohibitObjectsRequireNonNull);
GradleBuild withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {
for (Task task : Task.values()) {
configureTask(task, (configuration) -> configuration
.withProhibitObjectsRequireNonNull(prohibitObjectsRequireNonNull));
}
return this;
}
GradleBuild withConditionalOnClassAnnotation(String annotationName) {
for (Task task : Task.values()) {
configureTask(task, (configuration) -> configuration.withConditionalOnClassAnnotation(annotationName));
}
return this;
}
@ -423,6 +453,11 @@ class ArchitectureCheckTests { @@ -423,6 +453,11 @@ class ArchitectureCheckTests {
return this;
}
private void configureTask(Task task, UnaryOperator<TaskConfiguration> configurer) {
this.taskConfigurations.computeIfAbsent(task, (key) -> new TaskConfiguration(null, null));
this.taskConfigurations.compute(task, (key, value) -> configurer.apply(value));
}
private void configureNullMarkedExtension(UnaryOperator<NullMarkedExtension> configurer) {
NullMarkedExtension nullMarkedExtension = this.nullMarkedExtension;
if (nullMarkedExtension == null) {
@ -432,6 +467,7 @@ class ArchitectureCheckTests { @@ -432,6 +467,7 @@ class ArchitectureCheckTests {
}
GradleBuild withDependencies(String... dependencies) {
this.dependencies.clear();
this.dependencies.addAll(Arrays.asList(dependencies));
return this;
}
@ -460,15 +496,22 @@ class ArchitectureCheckTests { @@ -460,15 +496,22 @@ class ArchitectureCheckTests {
if (!this.dependencies.isEmpty()) {
buildFile.append("dependencies {\n");
for (String dependency : this.dependencies) {
buildFile.append(" implementation '%s'\n".formatted(dependency));
buildFile.append("\n implementation ").append(StringUtils.quote(dependency));
}
buildFile.append("}\n");
}
this.prohibitObjectsRequireNonNull.forEach((task, prohibitObjectsRequireNonNull) -> buildFile.append(task)
.append(" {\n")
.append(" prohibitObjectsRequireNonNull = ")
.append(prohibitObjectsRequireNonNull)
.append("\n}\n\n"));
this.taskConfigurations.forEach((task, configuration) -> {
buildFile.append(task).append(" {");
if (configuration.conditionalOnClassAnnotation() != null) {
buildFile.append("\n conditionalOnClassAnnotation = ")
.append(StringUtils.quote(configuration.conditionalOnClassAnnotation()));
}
if (configuration.prohibitObjectsRequireNonNull() != null) {
buildFile.append("\n prohibitObjectsRequireNonNull = ")
.append(configuration.prohibitObjectsRequireNonNull());
}
buildFile.append("\n}\n");
});
NullMarkedExtension nullMarkedExtension = this.nullMarkedExtension;
if (nullMarkedExtension != null) {
buildFile.append("architectureCheck {");
@ -505,6 +548,17 @@ class ArchitectureCheckTests { @@ -505,6 +548,17 @@ class ArchitectureCheckTests {
}
private record TaskConfiguration(Boolean prohibitObjectsRequireNonNull, String conditionalOnClassAnnotation) {
private TaskConfiguration withConditionalOnClassAnnotation(String annotationName) {
return new TaskConfiguration(this.prohibitObjectsRequireNonNull, annotationName);
}
private TaskConfiguration withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {
return new TaskConfiguration(prohibitObjectsRequireNonNull, this.conditionalOnClassAnnotation);
}
}
}
}

36
buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestConditionalOnClass.java

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/*
* Copyright 2012-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.architecture.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* {@code @ConditionalOnClass} analogue for architecture checks.
*
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface TestConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}

30
buildSrc/src/test/java/org/springframework/boot/build/architecture/conditionalonclass/OnBeanMethod.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/*
* Copyright 2012-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.architecture.conditionalonclass;
import org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;
import org.springframework.context.annotation.Bean;
class OnBeanMethod {
@Bean
@TestConditionalOnClass(String.class)
String helloWorld() {
return "Hello World";
}
}

2
documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/test-modules.adoc

@ -8,7 +8,7 @@ Spring Boot offers several focused, feature-specific `-test` modules: @@ -8,7 +8,7 @@ Spring Boot offers several focused, feature-specific `-test` modules:
|Module | Purpose
|`spring-boot-cache-test`
|Testing applications that use Spring Framework's cache abstration.
|Testing applications that use Spring Framework's cache abstraction.
|`spring-boot-data-cassandra-test`
|Testing applications that use Spring Data Cassandra. Provides the `@DataCassandraTest` test slice.

30
module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java

@ -51,6 +51,7 @@ import org.springframework.boot.autoconfigure.jmx.JmxProperties; @@ -51,6 +51,7 @@ import org.springframework.boot.autoconfigure.jmx.JmxProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
/**
@ -98,18 +99,6 @@ public final class JmxEndpointAutoConfiguration { @@ -98,18 +99,6 @@ public final class JmxEndpointAutoConfiguration {
return new DefaultEndpointObjectNameFactory(this.properties, this.jmxProperties, mBeanServer, contextId);
}
@Bean
@ConditionalOnSingleCandidate(MBeanServer.class)
@ConditionalOnClass(JsonMapper.class)
JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer, EndpointObjectNameFactory endpointObjectNameFactory,
ObjectProvider<JsonMapper> jsonMapper, JmxEndpointsSupplier jmxEndpointsSupplier) {
JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(jsonMapper.getIfAvailable());
return new JmxEndpointExporter(mBeanServer, endpointObjectNameFactory, responseMapper,
jmxEndpointsSupplier.getEndpoints());
}
// FIXME
@Bean
IncludeExcludeEndpointFilter<ExposableJmxEndpoint> jmxIncludeExcludePropertyEndpointFilter() {
JmxEndpointProperties.Exposure exposure = this.properties.getExposure();
@ -127,4 +116,21 @@ public final class JmxEndpointAutoConfiguration { @@ -127,4 +116,21 @@ public final class JmxEndpointAutoConfiguration {
return OperationFilter.byAccess(endpointAccessResolver);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JsonMapper.class)
static class JmxJacksonEndpointConfiguration {
@Bean
@ConditionalOnSingleCandidate(MBeanServer.class)
JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer,
EndpointObjectNameFactory endpointObjectNameFactory, ObjectProvider<JsonMapper> jsonMapper,
JmxEndpointsSupplier jmxEndpointsSupplier) {
JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(
jsonMapper.getIfAvailable());
return new JmxEndpointExporter(mBeanServer, endpointObjectNameFactory, responseMapper,
jmxEndpointsSupplier.getEndpoints());
}
}
}

52
module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayAutoConfiguration.java

@ -144,24 +144,6 @@ public final class FlywayAutoConfiguration { @@ -144,24 +144,6 @@ public final class FlywayAutoConfiguration {
return new PropertiesFlywayConnectionDetails(this.properties);
}
@Bean
@ConditionalOnClass(name = "org.flywaydb.database.sqlserver.SQLServerConfigurationExtension")
SqlServerFlywayConfigurationCustomizer sqlServerFlywayConfigurationCustomizer() {
return new SqlServerFlywayConfigurationCustomizer(this.properties);
}
@Bean
@ConditionalOnClass(name = "org.flywaydb.database.oracle.OracleConfigurationExtension")
OracleFlywayConfigurationCustomizer oracleFlywayConfigurationCustomizer() {
return new OracleFlywayConfigurationCustomizer(this.properties);
}
@Bean
@ConditionalOnClass(name = "org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension")
PostgresqlFlywayConfigurationCustomizer postgresqlFlywayConfigurationCustomizer() {
return new PostgresqlFlywayConfigurationCustomizer(this.properties);
}
@Bean
Flyway flyway(FlywayConnectionDetails connectionDetails, ResourceLoader resourceLoader,
ObjectProvider<DataSource> dataSource, @FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
@ -360,6 +342,40 @@ public final class FlywayAutoConfiguration { @@ -360,6 +342,40 @@ public final class FlywayAutoConfiguration {
return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
}
@ConditionalOnClass(name = "org.flywaydb.database.sqlserver.SQLServerConfigurationExtension")
@Configuration(proxyBeanMethods = false)
static class SqlServerConfiguration {
@Bean
SqlServerFlywayConfigurationCustomizer sqlServerFlywayConfigurationCustomizer(FlywayProperties properties) {
return new SqlServerFlywayConfigurationCustomizer(properties);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.flywaydb.database.oracle.OracleConfigurationExtension")
static class OracleConfiguration {
@Bean
OracleFlywayConfigurationCustomizer oracleFlywayConfigurationCustomizer(FlywayProperties properties) {
return new OracleFlywayConfigurationCustomizer(properties);
}
}
@ConditionalOnClass(name = "org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension")
@Configuration(proxyBeanMethods = false)
static class PostgresqlConfiguration {
@Bean
PostgresqlFlywayConfigurationCustomizer postgresqlFlywayConfigurationCustomizer(
FlywayProperties properties) {
return new PostgresqlFlywayConfigurationCustomizer(properties);
}
}
}
private static class LocationResolver {

2
module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesAutoConfigurationTests.java

@ -54,7 +54,7 @@ class AvailabilityProbesAutoConfigurationTests { @@ -54,7 +54,7 @@ class AvailabilityProbesAutoConfigurationTests {
}
@Test
void probesWhenNoActautorDependencyDoesNotAddBeans() {
void probesWhenNoActuatorDependencyDoesNotAddBeans() {
this.contextRunner.withClassLoader(new FilteredClassLoader(Endpoint.class.getName()))
.run(this::doesNotHaveProbeBeans);
}

20
module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java

@ -39,6 +39,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean @@ -39,6 +39,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.util.ClassUtils;
@ -98,14 +99,19 @@ public final class JvmMetricsAutoConfiguration { @@ -98,14 +99,19 @@ public final class JvmMetricsAutoConfiguration {
return new JvmCompilationMetrics();
}
@Bean
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = VIRTUAL_THREAD_METRICS_CLASS)
@ConditionalOnMissingBean(type = VIRTUAL_THREAD_METRICS_CLASS)
@ImportRuntimeHints(VirtualThreadMetricsRuntimeHintsRegistrar.class)
MeterBinder virtualThreadMetrics() throws ClassNotFoundException {
Class<?> virtualThreadMetricsClass = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS,
getClass().getClassLoader());
return (MeterBinder) BeanUtils.instantiateClass(virtualThreadMetricsClass);
static class VirtualThreadMetricsConfiguration {
@Bean
@ConditionalOnMissingBean(type = VIRTUAL_THREAD_METRICS_CLASS)
@ImportRuntimeHints(VirtualThreadMetricsRuntimeHintsRegistrar.class)
MeterBinder virtualThreadMetrics() throws ClassNotFoundException {
Class<?> virtualThreadMetricsClass = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS,
getClass().getClassLoader());
return (MeterBinder) BeanUtils.instantiateClass(virtualThreadMetricsClass);
}
}
static final class VirtualThreadMetricsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {

1
module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/SecurityRequestMatchersManagementContextConfiguration.java

@ -47,7 +47,6 @@ public class SecurityRequestMatchersManagementContextConfiguration { @@ -47,7 +47,6 @@ public class SecurityRequestMatchersManagementContextConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(DispatcherServlet.class)
public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {
return new PathPatternRequestMatcherProvider(servletPath::getRelativePath);
}

34
module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinAutoConfiguration.java

@ -31,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -31,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Zipkin.
@ -61,21 +62,26 @@ public final class ZipkinAutoConfiguration { @@ -61,21 +62,26 @@ public final class ZipkinAutoConfiguration {
};
}
@Bean
@ConditionalOnMissingBean(BytesMessageSender.class)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HttpClient.class)
ZipkinHttpClientSender httpClientSender(ZipkinProperties properties, Encoding encoding,
ObjectProvider<ZipkinHttpClientBuilderCustomizer> customizers,
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
Builder httpClientBuilder = HttpClient.newBuilder().connectTimeout(properties.getConnectTimeout());
customizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));
return new ZipkinHttpClientSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),
httpClientBuilder.build(), properties.getReadTimeout());
static class ZipkinHttpClientConfiguration {
@Bean
@ConditionalOnMissingBean(BytesMessageSender.class)
ZipkinHttpClientSender httpClientSender(ZipkinProperties properties, Encoding encoding,
ObjectProvider<ZipkinHttpClientBuilderCustomizer> customizers,
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
Builder httpClientBuilder = HttpClient.newBuilder().connectTimeout(properties.getConnectTimeout());
customizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));
return new ZipkinHttpClientSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),
httpClientBuilder.build(), properties.getReadTimeout());
}
}
}

Loading…
Cancel
Save