mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-25 02:49:03 +00:00
Merge branch '3.5.x'
Closes gh-47751
This commit is contained in:
+9
-2
@@ -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 {
|
||||
@Internal
|
||||
abstract SetProperty<String> getNullMarkedIgnoredPackages();
|
||||
|
||||
@Internal
|
||||
abstract Property<String> getConditionalOnClassAnnotation();
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -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("(**)")
|
||||
|
||||
+68
-14
@@ -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 {
|
||||
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 {
|
||||
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 {
|
||||
"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 {
|
||||
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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
}
|
||||
|
||||
GradleBuild withDependencies(String... dependencies) {
|
||||
this.dependencies.clear();
|
||||
this.dependencies.addAll(Arrays.asList(dependencies));
|
||||
return this;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
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
@@ -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
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+18
-12
@@ -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 {
|
||||
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 {
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+34
-18
@@ -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 {
|
||||
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 {
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ class AvailabilityProbesAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void probesWhenNoActautorDependencyDoesNotAddBeans() {
|
||||
void probesWhenNoActuatorDependencyDoesNotAddBeans() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(Endpoint.class.getName()))
|
||||
.run(this::doesNotHaveProbeBeans);
|
||||
}
|
||||
|
||||
+13
-7
@@ -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 {
|
||||
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
@@ -47,7 +47,6 @@ public class SecurityRequestMatchersManagementContextConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {
|
||||
return new PathPatternRequestMatcherProvider(servletPath::getRelativePath);
|
||||
}
|
||||
|
||||
+20
-14
@@ -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 {
|
||||
};
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user