From 4cb9d816b9d2d7be96048be11f717516b8f3c258 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 5 Feb 2025 16:05:19 +0000 Subject: [PATCH] Include non-default candidates in metrics and health Previously, when Actuator expected to find multiple beans of the same type, it used Map to inject them. Unfortunately, this does not include beans that are not default candidates and there's no way to request that autowiring includes such beans with Map-based injection. This commit switches from Map-based injection to querying the bean factory for the desired beans. This is done using SimpleAutowireCandidateResolver's new helper method, resolveAutowireCandidates, that returns a Map of beans including those that are not default candidates but excluding those that are not autowire candidates. Closes gh-43481 --- ...bitHealthContributorAutoConfiguration.java | 9 +-- .../CachesEndpointAutoConfiguration.java | 11 +-- ...sandraHealthContributorConfigurations.java | 7 +- ...aseHealthContributorAutoConfiguration.java | 9 +-- ...iveHealthContributorAutoConfiguration.java | 9 +-- ...iveHealthContributorAutoConfiguration.java | 9 +-- ...ngoHealthContributorAutoConfiguration.java | 9 +-- ...iveHealthContributorAutoConfiguration.java | 9 +-- ...disHealthContributorAutoConfiguration.java | 9 +-- ...iveHealthContributorAutoConfiguration.java | 10 +-- ...estHealthContributorAutoConfiguration.java | 9 +-- ...astHealthContributorAutoConfiguration.java | 9 +-- ...mpositeHealthContributorConfiguration.java | 16 +++- ...rceHealthContributorAutoConfiguration.java | 8 +- ...JmsHealthContributorAutoConfiguration.java | 9 +-- ...dapHealthContributorAutoConfiguration.java | 9 +-- ...ailHealthContributorAutoConfiguration.java | 9 +-- .../CacheMetricsRegistrarConfiguration.java | 8 +- ...ataSourcePoolMetricsAutoConfiguration.java | 10 ++- .../HibernateMetricsAutoConfiguration.java | 10 ++- ...onnectionPoolMetricsAutoConfiguration.java | 22 +++--- .../TaskExecutorMetricsAutoConfiguration.java | 25 +++--- .../Neo4jHealthContributorConfigurations.java | 13 ++-- ...oryHealthContributorAutoConfiguration.java | 14 ++-- ...teHealthContributorConfigurationTests.java | 77 ++++++++++++++++++- ...althContributorAutoConfigurationTests.java | 38 ++++++++- .../CacheMetricsAutoConfigurationTests.java | 59 +++++++++++++- ...urcePoolMetricsAutoConfigurationTests.java | 26 +++---- ...ibernateMetricsAutoConfigurationTests.java | 23 ++++-- ...tionPoolMetricsAutoConfigurationTests.java | 22 +++--- ...ExecutorMetricsAutoConfigurationTests.java | 72 ++++++++++++----- 31 files changed, 400 insertions(+), 179 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/amqp/RabbitHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/amqp/RabbitHealthContributorAutoConfiguration.java index 5a8a4810de8..cda828aa5dc 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/amqp/RabbitHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/amqp/RabbitHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,9 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.amqp; -import java.util.Map; - import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.amqp.RabbitHealthIndicator; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; @@ -50,8 +49,8 @@ public class RabbitHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "rabbitHealthIndicator", "rabbitHealthContributor" }) - public HealthContributor rabbitHealthContributor(Map rabbitTemplates) { - return createContributor(rabbitTemplates); + public HealthContributor rabbitHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, RabbitTemplate.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java index aa77bc8fdf2..61212d91e1a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java @@ -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. @@ -16,8 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.cache; -import java.util.Map; - +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure; import org.springframework.boot.actuate.cache.CachesEndpoint; @@ -45,8 +45,9 @@ public class CachesEndpointAutoConfiguration { @Bean @ConditionalOnMissingBean - public CachesEndpoint cachesEndpoint(Map cacheManagers) { - return new CachesEndpoint(cacheManagers); + public CachesEndpoint cachesEndpoint(ConfigurableListableBeanFactory beanFactory) { + return new CachesEndpoint( + SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, CacheManager.class)); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java index 570d5d08f1f..07a99e0537e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorConfigurations.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -20,6 +20,7 @@ import java.util.Map; import com.datastax.oss.driver.api.core.CqlSession; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.cassandra.CassandraDriverHealthIndicator; @@ -49,8 +50,8 @@ class CassandraHealthContributorConfigurations { @Bean @ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" }) - HealthContributor cassandraHealthContributor(Map sessions) { - return createContributor(sessions); + HealthContributor cassandraHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, CqlSession.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthContributorAutoConfiguration.java index 38a973a08c1..7ff6aa050ba 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.couchbase; -import java.util.Map; - import com.couchbase.client.java.Cluster; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator; @@ -55,8 +54,8 @@ public class CouchbaseHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "couchbaseHealthIndicator", "couchbaseHealthContributor" }) - public HealthContributor couchbaseHealthContributor(Map clusters) { - return createContributor(clusters); + public HealthContributor couchbaseHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, Cluster.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthContributorAutoConfiguration.java index 53fa4b4db7d..ee5c374095c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/couchbase/CouchbaseReactiveHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,11 +16,10 @@ package org.springframework.boot.actuate.autoconfigure.couchbase; -import java.util.Map; - import com.couchbase.client.java.Cluster; import reactor.core.publisher.Flux; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.couchbase.CouchbaseReactiveHealthIndicator; @@ -54,8 +53,8 @@ public class CouchbaseReactiveHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "couchbaseHealthIndicator", "couchbaseHealthContributor" }) - public ReactiveHealthContributor couchbaseHealthContributor(Map clusters) { - return createContributor(clusters); + public ReactiveHealthContributor couchbaseHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, Cluster.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfiguration.java index 484fede9ae9..9038a6cb956 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.data.elasticsearch; -import java.util.Map; - import reactor.core.publisher.Flux; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.data.elasticsearch.ElasticsearchReactiveHealthIndicator; @@ -54,8 +53,8 @@ public class ElasticsearchReactiveHealthContributorAutoConfiguration extends @Bean @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) - public ReactiveHealthContributor elasticsearchHealthContributor(Map clients) { - return createContributor(clients); + public ReactiveHealthContributor elasticsearchHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, ReactiveElasticsearchClient.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoHealthContributorAutoConfiguration.java index 8b65a9557d3..d125fce5e3f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.data.mongo; -import java.util.Map; - +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.data.mongo.MongoHealthIndicator; @@ -52,8 +51,8 @@ public class MongoHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "mongoHealthIndicator", "mongoHealthContributor" }) - public HealthContributor mongoHealthContributor(Map mongoTemplates) { - return createContributor(mongoTemplates); + public HealthContributor mongoHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, MongoTemplate.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoReactiveHealthContributorAutoConfiguration.java index eefc035b3c6..a89bd07200e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoReactiveHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/mongo/MongoReactiveHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.data.mongo; -import java.util.Map; - import reactor.core.publisher.Flux; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.data.mongo.MongoReactiveHealthIndicator; @@ -53,8 +52,8 @@ public class MongoReactiveHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "mongoHealthIndicator", "mongoHealthContributor" }) - public ReactiveHealthContributor mongoHealthContributor(Map reactiveMongoTemplates) { - return createContributor(reactiveMongoTemplates); + public ReactiveHealthContributor mongoHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, ReactiveMongoTemplate.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisHealthContributorAutoConfiguration.java index 76453afcdb6..22aacbbdb90 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.data.redis; -import java.util.Map; - +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.data.redis.RedisHealthIndicator; @@ -53,8 +52,8 @@ public class RedisHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "redisHealthIndicator", "redisHealthContributor" }) - public HealthContributor redisHealthContributor(Map redisConnectionFactories) { - return createContributor(redisConnectionFactories); + public HealthContributor redisHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, RedisConnectionFactory.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisReactiveHealthContributorAutoConfiguration.java index f2807de840d..3c06fd843ff 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisReactiveHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/data/redis/RedisReactiveHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -20,6 +20,7 @@ import java.util.Map; import reactor.core.publisher.Flux; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.data.redis.RedisReactiveHealthIndicator; @@ -50,18 +51,15 @@ import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; public class RedisReactiveHealthContributorAutoConfiguration extends CompositeReactiveHealthContributorConfiguration { - private final Map redisConnectionFactories; - RedisReactiveHealthContributorAutoConfiguration( Map redisConnectionFactories) { super(RedisReactiveHealthIndicator::new); - this.redisConnectionFactories = redisConnectionFactories; } @Bean @ConditionalOnMissingBean(name = { "redisHealthIndicator", "redisHealthContributor" }) - public ReactiveHealthContributor redisHealthContributor() { - return createContributor(this.redisConnectionFactories); + public ReactiveHealthContributor redisHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, ReactiveRedisConnectionFactory.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfiguration.java index b09f311ac0d..f698d81e398 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.elasticsearch; -import java.util.Map; - import org.elasticsearch.client.RestClient; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator; @@ -52,8 +51,8 @@ public class ElasticsearchRestHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) - public HealthContributor elasticsearchHealthContributor(Map clients) { - return createContributor(clients); + public HealthContributor elasticsearchHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, RestClient.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/hazelcast/HazelcastHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/hazelcast/HazelcastHealthContributorAutoConfiguration.java index 601f0c19564..51b4a503190 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/hazelcast/HazelcastHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/hazelcast/HazelcastHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.hazelcast; -import java.util.Map; - import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.hazelcast.HazelcastHealthIndicator; @@ -52,8 +51,8 @@ public class HazelcastHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "hazelcastHealthIndicator", "hazelcastHealthContributor" }) - public HealthContributor hazelcastHealthContributor(Map hazelcastInstances) { - return createContributor(hazelcastInstances); + public HealthContributor hazelcastHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, HazelcastInstance.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfiguration.java index 3b5aeda866d..73e414e8211 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -19,6 +19,8 @@ package org.springframework.boot.actuate.autoconfigure.health; import java.util.Map; import java.util.function.Function; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.util.Assert; /** @@ -46,6 +48,18 @@ public abstract class AbstractCompositeHealthContributorConfiguration beanType) { + return createContributor(SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, beanType)); + } + protected final C createContributor(Map beans) { Assert.notEmpty(beans, "Beans must not be empty"); if (beans.size() == 1) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java index a94172671e9..f6d2ee07861 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java @@ -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. @@ -28,6 +28,8 @@ import javax.sql.DataSource; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.health.CompositeHealthContributor; import org.springframework.boot.actuate.health.HealthContributor; @@ -84,8 +86,10 @@ public class DataSourceHealthContributorAutoConfiguration implements Initializin @Bean @ConditionalOnMissingBean(name = { "dbHealthIndicator", "dbHealthContributor" }) - public HealthContributor dbHealthContributor(Map dataSources, + public HealthContributor dbHealthContributor(ConfigurableListableBeanFactory beanFactory, DataSourceHealthIndicatorProperties dataSourceHealthIndicatorProperties) { + Map dataSources = SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, + DataSource.class); if (dataSourceHealthIndicatorProperties.isIgnoreRoutingDataSources()) { Map filteredDatasources = dataSources.entrySet() .stream() diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jms/JmsHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jms/JmsHealthContributorAutoConfiguration.java index aa7d72ab27a..afeb8123520 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jms/JmsHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jms/JmsHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.jms; -import java.util.Map; - import jakarta.jms.ConnectionFactory; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.health.HealthContributor; @@ -52,8 +51,8 @@ public class JmsHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "jmsHealthIndicator", "jmsHealthContributor" }) - public HealthContributor jmsHealthContributor(Map connectionFactories) { - return createContributor(connectionFactories); + public HealthContributor jmsHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, ConnectionFactory.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthContributorAutoConfiguration.java index e5de5e4b9fe..4163a8c065e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.ldap; -import java.util.Map; - +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.health.HealthContributor; @@ -51,8 +50,8 @@ public class LdapHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "ldapHealthIndicator", "ldapHealthContributor" }) - public HealthContributor ldapHealthContributor(Map ldapOperations) { - return createContributor(ldapOperations); + public HealthContributor ldapHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, LdapOperations.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mail/MailHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mail/MailHealthContributorAutoConfiguration.java index 89b61c72fe3..b99216b73a5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mail/MailHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/mail/MailHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.mail; -import java.util.Map; - +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.health.HealthContributor; @@ -50,8 +49,8 @@ public class MailHealthContributorAutoConfiguration @Bean @ConditionalOnMissingBean(name = { "mailHealthIndicator", "mailHealthContributor" }) - public HealthContributor mailHealthContributor(Map mailSenders) { - return createContributor(mailSenders); + public HealthContributor mailHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, JavaMailSenderImpl.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsRegistrarConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsRegistrarConfiguration.java index be54d5baf77..fd8e8de5f32 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsRegistrarConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsRegistrarConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -22,6 +22,8 @@ import java.util.Map; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.actuate.metrics.cache.CacheMeterBinderProvider; import org.springframework.boot.actuate.metrics.cache.CacheMetricsRegistrar; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -50,9 +52,9 @@ class CacheMetricsRegistrarConfiguration { private final Map cacheManagers; CacheMetricsRegistrarConfiguration(MeterRegistry registry, Collection> binderProviders, - Map cacheManagers) { + ConfigurableListableBeanFactory beanFactory) { this.registry = registry; - this.cacheManagers = cacheManagers; + this.cacheManagers = SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, CacheManager.class); this.cacheMetricsRegistrar = new CacheMetricsRegistrar(this.registry, binderProviders); bindCachesToRegistry(); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java index dfa11f953dd..adfe57d95dd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -32,6 +32,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.metrics.jdbc.DataSourcePoolMetrics; @@ -67,9 +69,11 @@ public class DataSourcePoolMetricsAutoConfiguration { private static final String DATASOURCE_SUFFIX = "dataSource"; @Bean - DataSourcePoolMetadataMeterBinder dataSourcePoolMetadataMeterBinder(Map dataSources, + DataSourcePoolMetadataMeterBinder dataSourcePoolMetadataMeterBinder(ConfigurableListableBeanFactory beanFactory, ObjectProvider metadataProviders) { - return new DataSourcePoolMetadataMeterBinder(dataSources, metadataProviders); + return new DataSourcePoolMetadataMeterBinder( + SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, DataSource.class), + metadataProviders); } static class DataSourcePoolMetadataMeterBinder implements MeterBinder { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java index 9de4febb50a..b0aa97ad641 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -26,6 +26,8 @@ import org.hibernate.SessionFactory; import org.hibernate.stat.HibernateMetrics; import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -57,9 +59,9 @@ public class HibernateMetricsAutoConfiguration implements SmartInitializingSingl private final MeterRegistry meterRegistry; - public HibernateMetricsAutoConfiguration(Map entityManagerFactories, - MeterRegistry meterRegistry) { - this.entityManagerFactories = entityManagerFactories; + public HibernateMetricsAutoConfiguration(ConfigurableListableBeanFactory beanFactory, MeterRegistry meterRegistry) { + this.entityManagerFactories = SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, + EntityManagerFactory.class); this.meterRegistry = meterRegistry; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfiguration.java index 6da2a37f51d..5328e331db1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,8 +16,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics.r2dbc; -import java.util.Map; - import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; import io.r2dbc.pool.ConnectionPool; @@ -25,6 +23,8 @@ import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.Wrapped; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.metrics.r2dbc.ConnectionPoolMetrics; @@ -49,14 +49,14 @@ import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; public class ConnectionPoolMetricsAutoConfiguration { @Autowired - public void bindConnectionPoolsToRegistry(Map connectionFactories, - MeterRegistry registry) { - connectionFactories.forEach((beanName, connectionFactory) -> { - ConnectionPool pool = extractPool(connectionFactory); - if (pool != null) { - new ConnectionPoolMetrics(pool, beanName, Tags.empty()).bindTo(registry); - } - }); + public void bindConnectionPoolsToRegistry(ConfigurableListableBeanFactory beanFactory, MeterRegistry registry) { + SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, ConnectionFactory.class) + .forEach((beanName, connectionFactory) -> { + ConnectionPool pool = extractPool(connectionFactory); + if (pool != null) { + new ConnectionPoolMetrics(pool, beanName, Tags.empty()).bindTo(registry); + } + }); } private ConnectionPool extractPool(Object candidate) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfiguration.java index 10c880d898e..e8d62ca0d6b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -17,7 +17,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics.task; import java.util.Collections; -import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; @@ -25,6 +24,8 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver; import org.springframework.boot.LazyInitializationExcludeFilter; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; @@ -35,6 +36,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration; import org.springframework.context.annotation.Bean; +import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @@ -54,15 +56,16 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; public class TaskExecutorMetricsAutoConfiguration { @Autowired - public void bindTaskExecutorsToRegistry(Map executors, MeterRegistry registry) { - executors.forEach((beanName, executor) -> { - if (executor instanceof ThreadPoolTaskExecutor threadPoolTaskExecutor) { - monitor(registry, safeGetThreadPoolExecutor(threadPoolTaskExecutor), beanName); - } - else if (executor instanceof ThreadPoolTaskScheduler threadPoolTaskScheduler) { - monitor(registry, safeGetThreadPoolExecutor(threadPoolTaskScheduler), beanName); - } - }); + public void bindTaskExecutorsToRegistry(ConfigurableListableBeanFactory beanFactory, MeterRegistry registry) { + SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, TaskExecutor.class) + .forEach((beanName, executor) -> { + if (executor instanceof ThreadPoolTaskExecutor threadPoolTaskExecutor) { + monitor(registry, safeGetThreadPoolExecutor(threadPoolTaskExecutor), beanName); + } + else if (executor instanceof ThreadPoolTaskScheduler threadPoolTaskScheduler) { + monitor(registry, safeGetThreadPoolExecutor(threadPoolTaskScheduler), beanName); + } + }); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/neo4j/Neo4jHealthContributorConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/neo4j/Neo4jHealthContributorConfigurations.java index 1f797f6bc7d..e76eb1d9a6a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/neo4j/Neo4jHealthContributorConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/neo4j/Neo4jHealthContributorConfigurations.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,11 +16,10 @@ package org.springframework.boot.actuate.autoconfigure.neo4j; -import java.util.Map; - import org.neo4j.driver.Driver; import reactor.core.publisher.Flux; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.health.HealthContributor; @@ -49,8 +48,8 @@ class Neo4jHealthContributorConfigurations { @Bean @ConditionalOnMissingBean(name = { "neo4jHealthIndicator", "neo4jHealthContributor" }) - HealthContributor neo4jHealthContributor(Map drivers) { - return createContributor(drivers); + HealthContributor neo4jHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, Driver.class); } } @@ -66,8 +65,8 @@ class Neo4jHealthContributorConfigurations { @Bean @ConditionalOnMissingBean(name = { "neo4jHealthIndicator", "neo4jHealthContributor" }) - ReactiveHealthContributor neo4jHealthContributor(Map drivers) { - return createContributor(drivers); + ReactiveHealthContributor neo4jHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, Driver.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/ConnectionFactoryHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/ConnectionFactoryHealthContributorAutoConfiguration.java index 90e8bc53605..53b66588c30 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/ConnectionFactoryHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/ConnectionFactoryHealthContributorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -16,10 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.r2dbc; -import java.util.Map; - import io.r2dbc.spi.ConnectionFactory; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.health.ReactiveHealthContributor; @@ -46,17 +45,14 @@ import org.springframework.context.annotation.Bean; public class ConnectionFactoryHealthContributorAutoConfiguration extends CompositeReactiveHealthContributorConfiguration { - private final Map connectionFactory; - - ConnectionFactoryHealthContributorAutoConfiguration(Map connectionFactory) { + ConnectionFactoryHealthContributorAutoConfiguration() { super(ConnectionFactoryHealthIndicator::new); - this.connectionFactory = connectionFactory; } @Bean @ConditionalOnMissingBean(name = { "r2dbcHealthIndicator", "r2dbcHealthContributor" }) - public ReactiveHealthContributor r2dbcHealthContributor() { - return createContributor(this.connectionFactory); + public ReactiveHealthContributor r2dbcHealthContributor(ConfigurableListableBeanFactory beanFactory) { + return createContributor(beanFactory, ConnectionFactory.class); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfigurationTests.java index e769d93ef3c..25ca3ec3e3e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/AbstractCompositeHealthContributorConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -23,6 +23,11 @@ import java.util.Map; import io.lettuce.core.dynamic.support.ResolvableType; import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.health.NamedContributor; +import org.springframework.boot.actuate.health.NamedContributors; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.util.ClassUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -69,10 +74,80 @@ abstract class AbstractCompositeHealthContributorConfigurationTests newComposite().createContributor(context.getBeanFactory(), TestBean.class)); + } + } + + @Test + void createContributorWhenBeanFactoryHasSingleBeanCreatesIndicator() { + try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { + context.register(SingleBeanConfiguration.class); + context.refresh(); + C contributor = newComposite().createContributor(context.getBeanFactory(), TestBean.class); + assertThat(contributor).isInstanceOf(this.indicatorType); + } + } + + @Test + void createContributorWhenBeanFactoryHasMultipleBeansCreatesComposite() { + try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { + context.register(MultipleBeansConfiguration.class); + context.refresh(); + C contributor = newComposite().createContributor(context.getBeanFactory(), TestBean.class); + assertThat(contributor).isNotInstanceOf(this.indicatorType); + assertThat(ClassUtils.getShortName(contributor.getClass())).startsWith("Composite"); + assertThat(((NamedContributors) contributor).stream().map(NamedContributor::getName)) + .containsExactlyInAnyOrder("standard", "nonDefault"); + } + } + protected abstract AbstractCompositeHealthContributorConfiguration newComposite(); static class TestBean { } + @Configuration(proxyBeanMethods = false) + static class MultipleBeansConfiguration { + + @Bean + TestBean standard() { + return new TestBean(); + } + + @Bean(defaultCandidate = false) + TestBean nonDefault() { + return new TestBean(); + + } + + @Bean(autowireCandidate = false) + TestBean nonAutowire() { + return new TestBean(); + + } + + } + + @Configuration(proxyBeanMethods = false) + static class SingleBeanConfiguration { + + @Bean + TestBean standard() { + return new TestBean(); + } + + @Bean(autowireCandidate = false) + TestBean nonAutowire() { + return new TestBean(); + + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java index bcbf8dc752b..ab76ba5c1ea 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java @@ -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. @@ -70,12 +70,14 @@ class DataSourceHealthContributorAutoConfigurationTests { @Test void runWhenMultipleDataSourceBeansShouldCreateCompositeIndicator() { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, DataSourceConfig.class) + this.contextRunner + .withUserConfiguration(EmbeddedDataSourceConfiguration.class, DataSourceConfig.class, + NonStandardDataSourceConfig.class) .run((context) -> { assertThat(context).hasSingleBean(CompositeHealthContributor.class); CompositeHealthContributor contributor = context.getBean(CompositeHealthContributor.class); String[] names = contributor.stream().map(NamedContributor::getName).toArray(String[]::new); - assertThat(names).containsExactlyInAnyOrder("dataSource", "testDataSource"); + assertThat(names).containsExactlyInAnyOrder("dataSource", "standardDataSource", "nonDefaultDataSource"); }); } @@ -217,7 +219,7 @@ class DataSourceHealthContributorAutoConfigurationTests { @Bean @ConfigurationProperties(prefix = "spring.datasource.test") - DataSource testDataSource() { + DataSource standardDataSource() { return DataSourceBuilder.create() .type(org.apache.tomcat.jdbc.pool.DataSource.class) .driverClassName("org.hsqldb.jdbc.JDBCDriver") @@ -228,6 +230,34 @@ class DataSourceHealthContributorAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + @EnableConfigurationProperties + static class NonStandardDataSourceConfig { + + @Bean(defaultCandidate = false) + @ConfigurationProperties(prefix = "spring.datasource.non-default") + DataSource nonDefaultDataSource() { + return DataSourceBuilder.create() + .type(org.apache.tomcat.jdbc.pool.DataSource.class) + .driverClassName("org.hsqldb.jdbc.JDBCDriver") + .url("jdbc:hsqldb:mem:non-default") + .username("sa") + .build(); + } + + @Bean(autowireCandidate = false) + @ConfigurationProperties(prefix = "spring.datasource.non-autowire") + DataSource nonAutowireDataSource() { + return DataSourceBuilder.create() + .type(org.apache.tomcat.jdbc.pool.DataSource.class) + .driverClassName("org.hsqldb.jdbc.JDBCDriver") + .url("jdbc:hsqldb:mem:non-autowire") + .username("sa") + .build(); + } + + } + @Configuration(proxyBeanMethods = false) static class RoutingDataSourceConfig { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java index 9cd4365df02..194b31f4be2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java @@ -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. @@ -16,6 +16,10 @@ package org.springframework.boot.actuate.autoconfigure.metrics.cache; +import java.util.Collections; +import java.util.List; + +import com.github.benmanes.caffeine.cache.CaffeineSpec; import io.micrometer.core.instrument.MeterRegistry; import org.junit.jupiter.api.Test; @@ -23,7 +27,12 @@ import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CachingConfigurer; import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.caffeine.CaffeineCacheManager; +import org.springframework.cache.interceptor.CacheResolver; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; @@ -91,6 +100,54 @@ class CacheMetricsAutoConfigurationTests { }); } + @Test + void customCacheManagersAreInstrumented() { + this.contextRunner + .withPropertyValues("spring.cache.type=caffeine", "spring.cache.cache-names=cache1,cache2", + "spring.cache.caffeine.spec=recordStats") + .withUserConfiguration(CustomCacheManagersConfiguration.class) + .run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("cache.gets").meters()).map((meter) -> meter.getId().getTag("cache")) + .containsOnly("standard", "non-default"); + }); + } + + @Configuration(proxyBeanMethods = false) + static class CustomCacheManagersConfiguration implements CachingConfigurer { + + @Bean + CacheManager standardCacheManager() { + CaffeineCacheManager cacheManager = new CaffeineCacheManager(); + cacheManager.setCaffeineSpec(CaffeineSpec.parse("recordStats")); + cacheManager.setCacheNames(List.of("standard")); + return cacheManager; + } + + @Bean(defaultCandidate = false) + CacheManager nonDefaultCacheManager() { + CaffeineCacheManager cacheManager = new CaffeineCacheManager(); + cacheManager.setCaffeineSpec(CaffeineSpec.parse("recordStats")); + cacheManager.setCacheNames(List.of("non-default")); + return cacheManager; + } + + @Bean(autowireCandidate = false) + CacheManager nonAutowireCacheManager() { + CaffeineCacheManager cacheManager = new CaffeineCacheManager(); + cacheManager.setCaffeineSpec(CaffeineSpec.parse("recordStats")); + cacheManager.setCacheNames(List.of("non-autowire")); + return cacheManager; + } + + @Bean + @Override + public CacheResolver cacheResolver() { + return (context) -> Collections.emptyList(); + } + + } + @Configuration(proxyBeanMethods = false) @EnableCaching static class CachingConfiguration { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfigurationTests.java index a20bd8ebd7e..06f4638bd6b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -86,11 +86,11 @@ class DataSourcePoolMetricsAutoConfigurationTests { this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) .withUserConfiguration(TwoDataSourcesConfiguration.class) .run((context) -> { - context.getBean("firstDataSource", DataSource.class).getConnection().getMetaData(); - context.getBean("secondOne", DataSource.class).getConnection().getMetaData(); + context.getBean("nonDefaultDataSource", DataSource.class).getConnection().getMetaData(); + context.getBean("nonAutowireDataSource", DataSource.class).getConnection().getMetaData(); MeterRegistry registry = context.getBean(MeterRegistry.class); - registry.get("jdbc.connections.max").tags("name", "first").meter(); - registry.get("jdbc.connections.max").tags("name", "secondOne").meter(); + assertThat(registry.find("jdbc.connections.max").meters()).map((meter) -> meter.getId().getTag("name")) + .containsOnly("dataSource", "nonDefault"); }); } @@ -101,11 +101,11 @@ class DataSourcePoolMetricsAutoConfigurationTests { (context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor())) .withUserConfiguration(TwoDataSourcesConfiguration.class) .run((context) -> { - context.getBean("firstDataSource", DataSource.class).getConnection().getMetaData(); - context.getBean("secondOne", DataSource.class).getConnection().getMetaData(); + context.getBean("nonDefaultDataSource", DataSource.class).getConnection().getMetaData(); + context.getBean("nonAutowireDataSource", DataSource.class).getConnection().getMetaData(); MeterRegistry registry = context.getBean(MeterRegistry.class); - registry.get("jdbc.connections.max").tags("name", "first").meter(); - registry.get("jdbc.connections.max").tags("name", "secondOne").meter(); + assertThat(registry.find("jdbc.connections.max").meters()).map((meter) -> meter.getId().getTag("name")) + .containsOnly("dataSource", "nonDefault"); }); } @@ -239,13 +239,13 @@ class DataSourcePoolMetricsAutoConfigurationTests { @Configuration(proxyBeanMethods = false) static class TwoDataSourcesConfiguration { - @Bean - DataSource firstDataSource() { + @Bean(defaultCandidate = false) + DataSource nonDefaultDataSource() { return createDataSource(); } - @Bean - DataSource secondOne() { + @Bean(autowireCandidate = false) + DataSource nonAutowireDataSource() { return createDataSource(); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java index 21d94348e14..651cfead8b0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -101,13 +101,15 @@ class HibernateMetricsAutoConfigurationTests { @Test void allEntityManagerFactoriesCanBeInstrumented() { this.contextRunner.withPropertyValues("spring.jpa.properties.hibernate.generate_statistics:true") - .withUserConfiguration(TwoEntityManagerFactoriesConfiguration.class) + .withUserConfiguration(MultipleEntityManagerFactoriesConfiguration.class) .run((context) -> { context.getBean("firstEntityManagerFactory", EntityManagerFactory.class).unwrap(SessionFactory.class); - context.getBean("secondOne", EntityManagerFactory.class).unwrap(SessionFactory.class); + context.getBean("nonDefault", EntityManagerFactory.class).unwrap(SessionFactory.class); + context.getBean("nonAutowire", EntityManagerFactory.class).unwrap(SessionFactory.class); MeterRegistry registry = context.getBean(MeterRegistry.class); - registry.get("hibernate.statements").tags("entityManagerFactory", "first").meter(); - registry.get("hibernate.statements").tags("entityManagerFactory", "secondOne").meter(); + assertThat(registry.find("hibernate.statements").meters()) + .map((meter) -> meter.getId().getTag("entityManagerFactory")) + .containsOnly("first", "nonDefault"); }); } @@ -171,7 +173,7 @@ class HibernateMetricsAutoConfigurationTests { } @Configuration(proxyBeanMethods = false) - static class TwoEntityManagerFactoriesConfiguration { + static class MultipleEntityManagerFactoriesConfiguration { private static final Class[] PACKAGE_CLASSES = new Class[] { MyEntity.class }; @@ -181,8 +183,13 @@ class HibernateMetricsAutoConfigurationTests { return createSessionFactory(ds); } - @Bean - LocalContainerEntityManagerFactoryBean secondOne(DataSource ds) { + @Bean(defaultCandidate = false) + LocalContainerEntityManagerFactoryBean nonDefault(DataSource ds) { + return createSessionFactory(ds); + } + + @Bean(autowireCandidate = false) + LocalContainerEntityManagerFactoryBean nonAutowire(DataSource ds) { return createSessionFactory(ds); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfigurationTests.java index de32507ba3e..df8fec77f28 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/r2dbc/ConnectionPoolMetricsAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -109,11 +109,10 @@ class ConnectionPoolMetricsAutoConfigurationTests { @Test void allConnectionPoolsCanBeInstrumented() { - this.contextRunner.withUserConfiguration(TwoConnectionPoolsConfiguration.class).run((context) -> { + this.contextRunner.withUserConfiguration(MultipleConnectionPoolsConfiguration.class).run((context) -> { MeterRegistry registry = context.getBean(MeterRegistry.class); - assertThat(registry.find("r2dbc.pool.acquired").gauges()).extracting(Meter::getId) - .extracting((id) -> id.getTag("name")) - .containsExactlyInAnyOrder("firstPool", "secondPool"); + assertThat(registry.find("r2dbc.pool.acquired").meters()).map((meter) -> meter.getId().getTag("name")) + .containsOnly("standardPool", "nonDefaultPool"); }); } @@ -179,7 +178,7 @@ class ConnectionPoolMetricsAutoConfigurationTests { } @Configuration(proxyBeanMethods = false) - static class TwoConnectionPoolsConfiguration { + static class MultipleConnectionPoolsConfiguration { @Bean CloseableConnectionFactory connectionFactory() { @@ -188,12 +187,17 @@ class ConnectionPoolMetricsAutoConfigurationTests { } @Bean - ConnectionPool firstPool(ConnectionFactory connectionFactory) { + ConnectionPool standardPool(ConnectionFactory connectionFactory) { return new ConnectionPool(ConnectionPoolConfiguration.builder(connectionFactory).build()); } - @Bean - ConnectionPool secondPool(ConnectionFactory connectionFactory) { + @Bean(defaultCandidate = false) + ConnectionPool nonDefaultPool(ConnectionFactory connectionFactory) { + return new ConnectionPool(ConnectionPoolConfiguration.builder(connectionFactory).build()); + } + + @Bean(autowireCandidate = false) + ConnectionPool nonAutowirePool(ConnectionFactory connectionFactory) { return new ConnectionPool(ConnectionPoolConfiguration.builder(connectionFactory).build()); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfigurationTests.java index 21c23e3bb78..8a6f061969a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/task/TaskExecutorMetricsAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 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. @@ -17,7 +17,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics.task; import java.util.Collection; -import java.util.concurrent.Executor; import io.micrometer.core.instrument.FunctionCounter; import io.micrometer.core.instrument.MeterRegistry; @@ -30,6 +29,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -82,14 +82,12 @@ class TaskExecutorMetricsAutoConfigurationTests { @Test void taskExecutorsWithCustomNamesAreInstrumented() { - this.contextRunner.withBean("firstTaskExecutor", Executor.class, ThreadPoolTaskExecutor::new) - .withBean("customName", ThreadPoolTaskExecutor.class, ThreadPoolTaskExecutor::new) - .run((context) -> { - MeterRegistry registry = context.getBean(MeterRegistry.class); - Collection meters = registry.get("executor.completed").functionCounters(); - assertThat(meters).map((meter) -> meter.getId().getTag("name")) - .containsExactlyInAnyOrder("firstTaskExecutor", "customName"); - }); + this.contextRunner.withUserConfiguration(MultipleTaskExecutorsConfiguration.class).run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + Collection meters = registry.get("executor.completed").functionCounters(); + assertThat(meters).map((meter) -> meter.getId().getTag("name")) + .containsExactlyInAnyOrder("standardTaskExecutor", "nonDefault"); + }); } @Test @@ -134,14 +132,12 @@ class TaskExecutorMetricsAutoConfigurationTests { @Test void taskSchedulersWithCustomNamesAreInstrumented() { - this.contextRunner.withBean("firstTaskScheduler", Executor.class, ThreadPoolTaskScheduler::new) - .withBean("customName", ThreadPoolTaskScheduler.class, ThreadPoolTaskScheduler::new) - .run((context) -> { - MeterRegistry registry = context.getBean(MeterRegistry.class); - Collection meters = registry.get("executor.completed").functionCounters(); - assertThat(meters).map((meter) -> meter.getId().getTag("name")) - .containsExactlyInAnyOrder("firstTaskScheduler", "customName"); - }); + this.contextRunner.withUserConfiguration(MultipleTaskSchedulersConfiguration.class).run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + Collection meters = registry.get("executor.completed").functionCounters(); + assertThat(meters).map((meter) -> meter.getId().getTag("name")) + .containsExactlyInAnyOrder("standardTaskScheduler", "nonDefault"); + }); } @Test @@ -176,4 +172,44 @@ class TaskExecutorMetricsAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class MultipleTaskSchedulersConfiguration { + + @Bean + ThreadPoolTaskScheduler standardTaskScheduler() { + return new ThreadPoolTaskScheduler(); + } + + @Bean(defaultCandidate = false) + ThreadPoolTaskScheduler nonDefault() { + return new ThreadPoolTaskScheduler(); + } + + @Bean(autowireCandidate = false) + ThreadPoolTaskScheduler nonAutowire() { + return new ThreadPoolTaskScheduler(); + } + + } + + @Configuration(proxyBeanMethods = false) + static class MultipleTaskExecutorsConfiguration { + + @Bean + ThreadPoolTaskExecutor standardTaskExecutor() { + return new ThreadPoolTaskExecutor(); + } + + @Bean(defaultCandidate = false) + ThreadPoolTaskExecutor nonDefault() { + return new ThreadPoolTaskExecutor(); + } + + @Bean(autowireCandidate = false) + ThreadPoolTaskExecutor nonAutowire() { + return new ThreadPoolTaskExecutor(); + } + + } + }