Avoid using reflection when creating composite health contributors

Closes gh-32541
This commit is contained in:
Andy Wilkinson 2022-09-29 14:16:50 +01:00
parent e2dd0ef9a4
commit bcb5e84129
24 changed files with 277 additions and 22 deletions

View File

@ -44,6 +44,10 @@ import org.springframework.context.annotation.Bean;
public class RabbitHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<RabbitHealthIndicator, RabbitTemplate> {
public RabbitHealthContributorAutoConfiguration() {
super(RabbitHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "rabbitHealthIndicator", "rabbitHealthContributor" })
public HealthContributor rabbitHealthContributor(Map<String, RabbitTemplate> rabbitTemplates) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -43,6 +43,10 @@ class CassandraHealthContributorConfigurations {
static class CassandraDriverConfiguration
extends CompositeHealthContributorConfiguration<CassandraDriverHealthIndicator, CqlSession> {
CassandraDriverConfiguration() {
super(CassandraDriverHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" })
HealthContributor cassandraHealthContributor(Map<String, CqlSession> sessions) {
@ -56,6 +60,10 @@ class CassandraHealthContributorConfigurations {
static class CassandraReactiveDriverConfiguration extends
CompositeReactiveHealthContributorConfiguration<CassandraDriverReactiveHealthIndicator, CqlSession> {
CassandraReactiveDriverConfiguration() {
super(CassandraDriverReactiveHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" })
ReactiveHealthContributor cassandraHealthContributor(Map<String, CqlSession> sessions) {

View File

@ -49,6 +49,10 @@ import org.springframework.context.annotation.Bean;
public class CouchbaseHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<CouchbaseHealthIndicator, Cluster> {
public CouchbaseHealthContributorAutoConfiguration() {
super(CouchbaseHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "couchbaseHealthIndicator", "couchbaseHealthContributor" })
public HealthContributor couchbaseHealthContributor(Map<String, Cluster> clusters) {

View File

@ -48,6 +48,10 @@ import org.springframework.context.annotation.Bean;
public class CouchbaseReactiveHealthContributorAutoConfiguration
extends CompositeReactiveHealthContributorConfiguration<CouchbaseReactiveHealthIndicator, Cluster> {
public CouchbaseReactiveHealthContributorAutoConfiguration() {
super(CouchbaseReactiveHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "couchbaseHealthIndicator", "couchbaseHealthContributor" })
public ReactiveHealthContributor couchbaseHealthContributor(Map<String, Cluster> clusters) {

View File

@ -48,6 +48,10 @@ import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchCl
public class ElasticsearchReactiveHealthContributorAutoConfiguration extends
CompositeReactiveHealthContributorConfiguration<ElasticsearchReactiveHealthIndicator, ReactiveElasticsearchClient> {
public ElasticsearchReactiveHealthContributorAutoConfiguration() {
super(ElasticsearchReactiveHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" })
public ReactiveHealthContributor elasticsearchHealthContributor(Map<String, ReactiveElasticsearchClient> clients) {

View File

@ -46,6 +46,10 @@ import org.springframework.data.mongodb.core.MongoTemplate;
public class MongoHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<MongoHealthIndicator, MongoTemplate> {
public MongoHealthContributorAutoConfiguration() {
super(MongoHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "mongoHealthIndicator", "mongoHealthContributor" })
public HealthContributor mongoHealthContributor(Map<String, MongoTemplate> mongoTemplates) {

View File

@ -47,6 +47,10 @@ import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
public class MongoReactiveHealthContributorAutoConfiguration
extends CompositeReactiveHealthContributorConfiguration<MongoReactiveHealthIndicator, ReactiveMongoTemplate> {
public MongoReactiveHealthContributorAutoConfiguration() {
super(MongoReactiveHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "mongoHealthIndicator", "mongoHealthContributor" })
public ReactiveHealthContributor mongoHealthContributor(Map<String, ReactiveMongoTemplate> reactiveMongoTemplates) {

View File

@ -47,6 +47,10 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
public class RedisHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<RedisHealthIndicator, RedisConnectionFactory> {
RedisHealthContributorAutoConfiguration() {
super(RedisHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "redisHealthIndicator", "redisHealthContributor" })
public HealthContributor redisHealthContributor(Map<String, RedisConnectionFactory> redisConnectionFactories) {

View File

@ -54,6 +54,7 @@ public class RedisReactiveHealthContributorAutoConfiguration extends
RedisReactiveHealthContributorAutoConfiguration(
Map<String, ReactiveRedisConnectionFactory> redisConnectionFactories) {
super(RedisReactiveHealthIndicator::new);
this.redisConnectionFactories = redisConnectionFactories;
}

View File

@ -46,6 +46,10 @@ import org.springframework.context.annotation.Bean;
public class ElasticsearchRestHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> {
public ElasticsearchRestHealthContributorAutoConfiguration() {
super(ElasticsearchRestClientHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" })
public HealthContributor elasticsearchHealthContributor(Map<String, RestClient> clients) {

View File

@ -46,6 +46,10 @@ import org.springframework.context.annotation.Bean;
public class HazelcastHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<HazelcastHealthIndicator, HazelcastInstance> {
public HazelcastHealthContributorAutoConfiguration() {
super(HazelcastHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "hazelcastHealthIndicator", "hazelcastHealthContributor" })
public HealthContributor hazelcastHealthContributor(Map<String, HazelcastInstance> hazelcastInstances) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 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.
@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.health;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.function.Function;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ResolvableType;
@ -36,16 +37,41 @@ import org.springframework.util.Assert;
*/
public abstract class AbstractCompositeHealthContributorConfiguration<C, I extends C, B> {
private final Class<?> indicatorType;
private final Function<B, I> indicatorFactory;
private final Class<?> beanType;
AbstractCompositeHealthContributorConfiguration() {
/**
* Creates a {@code AbstractCompositeHealthContributorConfiguration} that will use
* reflection to create health indicator instances.
* @deprecated since 3.0.0 in favor of
* {@link #AbstractCompositeHealthContributorConfiguration(Function)}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
protected AbstractCompositeHealthContributorConfiguration() {
ResolvableType type = ResolvableType.forClass(AbstractCompositeHealthContributorConfiguration.class,
getClass());
this.indicatorType = type.resolveGeneric(1);
this.beanType = type.resolveGeneric(2);
Class<?> indicatorType = type.resolveGeneric(1);
Class<?> beanType = type.resolveGeneric(2);
this.indicatorFactory = (bean) -> {
try {
@SuppressWarnings("unchecked")
Constructor<I> constructor = (Constructor<I>) indicatorType.getDeclaredConstructor(beanType);
return BeanUtils.instantiateClass(constructor, bean);
}
catch (Exception ex) {
throw new IllegalStateException(
"Unable to create health indicator " + indicatorType + " for bean type " + beanType, ex);
}
};
}
/**
* Creates a {@code AbstractCompositeHealthContributorConfiguration} that will use the
* given {@code indicatorFactory} to create health indicator instances.
* @param indicatorFactory the function to create health indicators
* @since 3.0.0
*/
protected AbstractCompositeHealthContributorConfiguration(Function<B, I> indicatorFactory) {
this.indicatorFactory = indicatorFactory;
}
protected final C createContributor(Map<String, B> beans) {
@ -58,16 +84,8 @@ public abstract class AbstractCompositeHealthContributorConfiguration<C, I exten
protected abstract C createComposite(Map<String, B> beans);
@SuppressWarnings("unchecked")
protected I createIndicator(B bean) {
try {
Constructor<I> constructor = (Constructor<I>) this.indicatorType.getDeclaredConstructor(this.beanType);
return BeanUtils.instantiateClass(constructor, bean);
}
catch (Exception ex) {
throw new IllegalStateException(
"Unable to create health indicator " + this.indicatorType + " for bean type " + this.beanType, ex);
}
return this.indicatorFactory.apply(bean);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 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,6 +17,7 @@
package org.springframework.boot.actuate.autoconfigure.health;
import java.util.Map;
import java.util.function.Function;
import org.springframework.boot.actuate.health.CompositeHealthContributor;
import org.springframework.boot.actuate.health.HealthContributor;
@ -35,6 +36,27 @@ import org.springframework.boot.actuate.health.HealthIndicator;
public abstract class CompositeHealthContributorConfiguration<I extends HealthIndicator, B>
extends AbstractCompositeHealthContributorConfiguration<HealthContributor, I, B> {
/**
* Creates a {@code CompositeHealthContributorConfiguration} that will use reflection
* to create {@link HealthIndicator} instances.
* @deprecated since 3.0.0 in favor of
* {@link #CompositeHealthContributorConfiguration(Function)}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public CompositeHealthContributorConfiguration() {
super();
}
/**
* Creates a {@code CompositeHealthContributorConfiguration} that will use the given
* {@code indicatorFactory} to create {@link HealthIndicator} instances.
* @param indicatorFactory the function to create health indicator instances
* @since 3.0.0
*/
public CompositeHealthContributorConfiguration(Function<B, I> indicatorFactory) {
super(indicatorFactory);
}
@Override
protected final HealthContributor createComposite(Map<String, B> beans) {
return CompositeHealthContributor.fromMap(beans, this::createIndicator);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 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,6 +17,7 @@
package org.springframework.boot.actuate.autoconfigure.health;
import java.util.Map;
import java.util.function.Function;
import org.springframework.boot.actuate.health.CompositeReactiveHealthContributor;
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
@ -35,6 +36,27 @@ import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
public abstract class CompositeReactiveHealthContributorConfiguration<I extends ReactiveHealthIndicator, B>
extends AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, I, B> {
/**
* Creates a {@code CompositeReactiveHealthContributorConfiguration} that will use
* reflection to create {@link ReactiveHealthIndicator} instances.
* @deprecated since 3.0.0 in favor of
* {@link #CompositeReactiveHealthContributorConfiguration(Function)}
*/
@Deprecated(since = "3.0.0", forRemoval = true)
public CompositeReactiveHealthContributorConfiguration() {
super();
}
/**
* Creates a {@code CompositeReactiveHealthContributorConfiguration} that will use the
* given {@code indicatorFactory} to create {@link ReactiveHealthIndicator} instances.
* @param indicatorFactory the function to create health indicator instances
* @since 3.0.0
*/
public CompositeReactiveHealthContributorConfiguration(Function<B, I> indicatorFactory) {
super(indicatorFactory);
}
@Override
protected final ReactiveHealthContributor createComposite(Map<String, B> beans) {
return CompositeReactiveHealthContributor.fromMap(beans, this::createIndicator);

View File

@ -45,6 +45,10 @@ import org.springframework.context.annotation.Bean;
public class InfluxDbHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<InfluxDbHealthIndicator, InfluxDB> {
public InfluxDbHealthContributorAutoConfiguration() {
super(InfluxDbHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "influxDbHealthIndicator", "influxDbHealthContributor" })
public HealthContributor influxDbHealthContributor(Map<String, InfluxDB> influxDbs) {

View File

@ -45,6 +45,10 @@ import org.springframework.context.annotation.Bean;
public class JmsHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<JmsHealthIndicator, ConnectionFactory> {
public JmsHealthContributorAutoConfiguration() {
super(JmsHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "jmsHealthIndicator", "jmsHealthContributor" })
public HealthContributor jmsHealthContributor(Map<String, ConnectionFactory> connectionFactories) {

View File

@ -45,6 +45,10 @@ import org.springframework.ldap.core.LdapOperations;
public class LdapHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<LdapHealthIndicator, LdapOperations> {
public LdapHealthContributorAutoConfiguration() {
super(LdapHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "ldapHealthIndicator", "ldapHealthContributor" })
public HealthContributor ldapHealthContributor(Map<String, LdapOperations> ldapOperations) {

View File

@ -44,6 +44,10 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
public class MailHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<MailHealthIndicator, JavaMailSenderImpl> {
public MailHealthContributorAutoConfiguration() {
super(MailHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "mailHealthIndicator", "mailHealthContributor" })
public HealthContributor mailHealthContributor(Map<String, JavaMailSenderImpl> mailSenders) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
@ -43,6 +43,10 @@ class Neo4jHealthContributorConfigurations {
@Configuration(proxyBeanMethods = false)
static class Neo4jConfiguration extends CompositeHealthContributorConfiguration<Neo4jHealthIndicator, Driver> {
Neo4jConfiguration() {
super(Neo4jHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "neo4jHealthIndicator", "neo4jHealthContributor" })
HealthContributor neo4jHealthContributor(Map<String, Driver> drivers) {
@ -56,6 +60,10 @@ class Neo4jHealthContributorConfigurations {
static class Neo4jReactiveConfiguration
extends CompositeReactiveHealthContributorConfiguration<Neo4jReactiveHealthIndicator, Driver> {
Neo4jReactiveConfiguration() {
super(Neo4jReactiveHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "neo4jHealthIndicator", "neo4jHealthContributor" })
ReactiveHealthContributor neo4jHealthContributor(Map<String, Driver> drivers) {

View File

@ -49,6 +49,7 @@ public class ConnectionFactoryHealthContributorAutoConfiguration
private final Map<String, ConnectionFactory> connectionFactory;
ConnectionFactoryHealthContributorAutoConfiguration(Map<String, ConnectionFactory> connectionFactory) {
super(ConnectionFactoryHealthIndicator::new);
this.connectionFactory = connectionFactory;
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2012-2022 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.actuate.autoconfigure.health;
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfigurationReflectionTests.TestHealthIndicator;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.actuate.health.HealthContributor;
/**
* Tests for {@link CompositeHealthContributorConfiguration} using reflection to create
* indicator instances.
*
* @author Phillip Webb
*/
@Deprecated(since = "3.0.0", forRemoval = true)
class CompositeHealthContributorConfigurationReflectionTests
extends AbstractCompositeHealthContributorConfigurationTests<HealthContributor, TestHealthIndicator> {
@Override
protected AbstractCompositeHealthContributorConfiguration<HealthContributor, TestHealthIndicator, TestBean> newComposite() {
return new ReflectiveTestCompositeHealthContributorConfiguration();
}
static class ReflectiveTestCompositeHealthContributorConfiguration
extends CompositeHealthContributorConfiguration<TestHealthIndicator, TestBean> {
}
static class TestHealthIndicator extends AbstractHealthIndicator {
TestHealthIndicator(TestBean testBean) {
}
@Override
protected void doHealthCheck(Builder builder) throws Exception {
builder.up();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 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.
@ -37,6 +37,10 @@ class CompositeHealthContributorConfigurationTests
static class TestCompositeHealthContributorConfiguration
extends CompositeHealthContributorConfiguration<TestHealthIndicator, TestBean> {
TestCompositeHealthContributorConfiguration() {
super(TestHealthIndicator::new);
}
}
static class TestHealthIndicator extends AbstractHealthIndicator {

View File

@ -0,0 +1,59 @@
/*
* Copyright 2012-2022 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.actuate.autoconfigure.health;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfigurationReflectionTests.TestReactiveHealthIndicator;
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
/**
* Tests for {@link CompositeReactiveHealthContributorConfiguration} using reflection to
* create indicator instances.
*
* @author Phillip Webb
*/
@Deprecated(since = "3.0.0", forRemoval = true)
class CompositeReactiveHealthContributorConfigurationReflectionTests extends
AbstractCompositeHealthContributorConfigurationTests<ReactiveHealthContributor, TestReactiveHealthIndicator> {
@Override
protected AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, TestReactiveHealthIndicator, TestBean> newComposite() {
return new TestCompositeReactiveHealthContributorConfiguration();
}
static class TestCompositeReactiveHealthContributorConfiguration
extends CompositeReactiveHealthContributorConfiguration<TestReactiveHealthIndicator, TestBean> {
}
static class TestReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
TestReactiveHealthIndicator(TestBean testBean) {
}
@Override
protected Mono<Health> doHealthCheck(Builder builder) {
return Mono.just(builder.up().build());
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 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.
@ -40,6 +40,10 @@ class CompositeReactiveHealthContributorConfigurationTests extends
static class TestCompositeReactiveHealthContributorConfiguration
extends CompositeReactiveHealthContributorConfiguration<TestReactiveHealthIndicator, TestBean> {
TestCompositeReactiveHealthContributorConfiguration() {
super(TestReactiveHealthIndicator::new);
}
}
static class TestReactiveHealthIndicator extends AbstractReactiveHealthIndicator {