GH-2612 Fix initialization ordering issue with actuator endpoints

this also includes improvement where channels are now retrieved dynamically allowing new channels created during the runtime of the application to be visible as well
Resolves #2612
This commit is contained in:
Oleg Zhurakousky
2023-01-19 15:13:22 +01:00
parent 02241661a5
commit 6f86e28b48
2 changed files with 20 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 the original author or authors.
* Copyright 2015-2023 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,16 +16,12 @@
package org.springframework.cloud.stream.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.stream.binding.Bindable;
import org.springframework.cloud.stream.binding.BindingService;
import org.springframework.cloud.stream.endpoint.ChannelsEndpoint;
import org.springframework.context.annotation.Bean;
@@ -34,6 +30,7 @@ import org.springframework.context.annotation.Bean;
* @author Dave Syer
* @author Marius Bogoevici
* @author Ilayaperumal Gopinathan
* @author Oleg Zhurakousky
*/
@AutoConfiguration
@ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.annotation.Endpoint")
@@ -41,13 +38,10 @@ import org.springframework.context.annotation.Bean;
@AutoConfigureAfter(EndpointAutoConfiguration.class)
public class ChannelsEndpointAutoConfiguration {
@Autowired(required = false)
private List<Bindable> adapters;
@Bean
@ConditionalOnAvailableEndpoint
public ChannelsEndpoint channelsEndpoint(BindingServiceProperties properties) {
return new ChannelsEndpoint(this.adapters, properties);
return new ChannelsEndpoint(properties);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2016 the original author or authors.
* Copyright 2015-2023 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.cloud.stream.endpoint;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -25,11 +25,14 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeansException;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.stream.binding.Bindable;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.BindingServiceProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* An {@link Endpoint} that has the binding information on all the {@link Bindable}
@@ -38,26 +41,31 @@ import org.springframework.cloud.stream.config.BindingServiceProperties;
* @author Dave Syer
* @author Ilayaperumal Gopinathan
* @author Vinicius Carvalho
* @author Oleg Zhurakousky
*/
@Endpoint(id = "channels")
public class ChannelsEndpoint {
public class ChannelsEndpoint implements ApplicationContextAware {
private List<Bindable> adapters;
private ApplicationContext applicationContext;
private BindingServiceProperties properties;
private final BindingServiceProperties properties;
public ChannelsEndpoint(List<Bindable> adapters,
BindingServiceProperties properties) {
this.adapters = adapters;
public ChannelsEndpoint(BindingServiceProperties properties) {
this.properties = properties;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@ReadOperation
public Map<String, Object> channels() {
Collection<Bindable> adapters = applicationContext.getBeansOfType(Bindable.class).values();
ChannelsMetaData map = new ChannelsMetaData();
Map<String, BindingProperties> inputs = map.getInputs();
Map<String, BindingProperties> outputs = map.getOutputs();
for (Bindable factory : this.adapters) {
for (Bindable factory : adapters) {
for (String name : factory.getInputs()) {
inputs.put(name, this.properties.getBindingProperties(name));
}