Skip to content

Commit 3dae351

Browse files
committed
GH-3166 Initial support for explicit Binding creation
1 parent 1adb517 commit 3dae351

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/BindingsLifecycleController.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.Collection;
21+
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.Map;
2324
import java.util.stream.Collectors;
@@ -31,10 +32,15 @@
3132
import org.springframework.beans.BeansException;
3233
import org.springframework.beans.DirectFieldAccessor;
3334
import org.springframework.cloud.stream.binder.Binding;
35+
import org.springframework.cloud.stream.binder.DefaultBinderFactory;
36+
import org.springframework.cloud.stream.binder.ExtendedPropertiesBinder;
37+
import org.springframework.cloud.stream.config.BindingProperties;
38+
import org.springframework.cloud.stream.config.BindingServiceProperties;
3439
import org.springframework.cloud.stream.function.BindableFunctionProxyFactory;
3540
import org.springframework.cloud.stream.function.StreamFunctionProperties;
3641
import org.springframework.context.ApplicationContext;
3742
import org.springframework.context.ApplicationContextAware;
43+
import org.springframework.messaging.MessageChannel;
3844
import org.springframework.util.Assert;
3945
import org.springframework.util.ClassUtils;
4046
import org.springframework.util.CollectionUtils;
@@ -86,6 +92,57 @@ public BindingsLifecycleController(List<InputBindingLifecycle> inputBindingLifec
8692
this.objectMapper = builder.build();
8793
}
8894
}
95+
96+
/**
97+
* Allows to dynamically create a new input binding returning its consumer properties for further customization.
98+
* Unlike {@link #defineBinding(BindableFunctionProxyFactory)} this method will not initialize the binding.
99+
* You have to call {@link #defineBinding(BindableFunctionProxyFactory)} explicitly after you create a binding.
100+
* @param <P> the type of consumer properties. For example, if binding derives from Kafka, it will return KafkaConsumerProperties.
101+
* @param bindingName the name of the binding.
102+
* @param binderName the name of the binder.
103+
* @param bindingProperties instance of BindingProperties.
104+
* @return instance of the consumer properties.
105+
*/
106+
@SuppressWarnings("unchecked")
107+
public <P> P createInputBinding(String bindingName, String binderName, BindingProperties bindingProperties) {
108+
Assert.hasText(bindingProperties.getGroup(), "Anonymous bindings are not allowed for explicit creation. You must define 'group'");
109+
DefaultBinderFactory binderFactory = this.applicationContext.getBean(DefaultBinderFactory.class);
110+
Object binder = binderFactory.getBinder(binderName, MessageChannel.class);
111+
BindingServiceProperties bindingServiceProperties = this.applicationContext.getBean(BindingServiceProperties.class);
112+
bindingServiceProperties.setBindings(Collections.singletonMap(bindingName, bindingProperties));
113+
if (binder instanceof ExtendedPropertiesBinder extendedPropertiesBinder) {
114+
Object extensionPropertries = extendedPropertiesBinder.getExtendedConsumerProperties(bindingName);
115+
return (P) extensionPropertries;
116+
}
117+
else {
118+
throw new IllegalStateException("Binder must be an instance of ExtendedPropertiesBinder");
119+
}
120+
}
121+
122+
/**
123+
* Allows to dynamically create a new input binding returning its consumer properties for further customization.
124+
* Unlike {@link #defineBinding(BindableFunctionProxyFactory)} this method will not initialize the binding.
125+
* You have to call {@link #defineBinding(BindableFunctionProxyFactory)} explicitly after you create a binding.
126+
* @param <P> the type of consumer properties. For example, if binding derives from Kafka, it will return KafkaConsumerProperties.
127+
* @param bindingName the name of the binding.
128+
* @param binderName the name of the binder.
129+
* @param bindingProperties instance of BindingProperties.
130+
* @return instance of the consumer properties.
131+
*/
132+
@SuppressWarnings("unchecked")
133+
public <P> P createOutputBinding(String bindingName, String binderName, BindingProperties bindingProperties) {
134+
DefaultBinderFactory binderFactory = this.applicationContext.getBean(DefaultBinderFactory.class);
135+
Object binder = binderFactory.getBinder(binderName, MessageChannel.class);
136+
BindingServiceProperties bindingServiceProperties = this.applicationContext.getBean(BindingServiceProperties.class);
137+
bindingServiceProperties.setBindings(Collections.singletonMap(bindingName, bindingProperties));
138+
if (binder instanceof ExtendedPropertiesBinder extendedPropertiesBinder) {
139+
Object extensionPropertries = extendedPropertiesBinder.getExtendedProducerProperties(bindingName);
140+
return (P) extensionPropertries;
141+
}
142+
else {
143+
throw new IllegalStateException("Binder must be an instance of ExtendedPropertiesBinder");
144+
}
145+
}
89146

90147
/**
91148
* Allows to dynamically define a new input binding returning its consumer properties for further customization.

0 commit comments

Comments
 (0)