32
32
import java .util .concurrent .TimeUnit ;
33
33
import java .util .concurrent .TimeoutException ;
34
34
import java .util .concurrent .atomic .AtomicInteger ;
35
+ import java .util .function .Predicate ;
35
36
import java .util .stream .Collectors ;
36
37
37
38
import org .apache .commons .logging .LogFactory ;
62
63
import org .springframework .kafka .KafkaException ;
63
64
import org .springframework .kafka .support .TopicForRetryable ;
64
65
import org .springframework .lang .Nullable ;
66
+ import org .springframework .util .Assert ;
65
67
66
68
/**
67
69
* An admin that delegates to an {@link AdminClient} to create topics defined
@@ -88,6 +90,8 @@ public class KafkaAdmin extends KafkaResourceFactory
88
90
89
91
private ApplicationContext applicationContext ;
90
92
93
+ private Predicate <NewTopic > createOrModifyTopic = nt -> true ;
94
+
91
95
private Duration closeTimeout = DEFAULT_CLOSE_TIMEOUT ;
92
96
93
97
private int operationTimeout = DEFAULT_OPERATION_TIMEOUT ;
@@ -169,6 +173,31 @@ public void setModifyTopicConfigs(boolean modifyTopicConfigs) {
169
173
this .modifyTopicConfigs = modifyTopicConfigs ;
170
174
}
171
175
176
+ /**
177
+ * Set a predicate that returns true if a discovered {@link NewTopic} bean should be
178
+ * considered for creation or modification by this admin instance. The default
179
+ * predicate returns true for all {@link NewTopic}s. Used by the default
180
+ * implementation of {@link #newTopics()}.
181
+ * @param createOrModifyTopic the predicate.
182
+ * @since 2.9.10
183
+ * @see #newTopics()
184
+ */
185
+ public void setCreateOrModifyTopic (Predicate <NewTopic > createOrModifyTopic ) {
186
+ Assert .notNull (createOrModifyTopic , "'createOrModifyTopic' cannot be null" );
187
+ this .createOrModifyTopic = createOrModifyTopic ;
188
+ }
189
+
190
+ /**
191
+ * Return the predicate used to determine whether a {@link NewTopic} should be
192
+ * considered for creation or modification.
193
+ * @return the predicate.
194
+ * @since 2.9.10
195
+ * @see #newTopics()
196
+ */
197
+ protected Predicate <NewTopic > getCreateOrModifyTopic () {
198
+ return this .createOrModifyTopic ;
199
+ }
200
+
172
201
@ Override
173
202
public Map <String , Object > getConfigurationProperties () {
174
203
Map <String , Object > configs2 = new HashMap <>(this .configs );
@@ -238,10 +267,17 @@ public final boolean initialize() {
238
267
return false ;
239
268
}
240
269
241
- /*
242
- * Remove any TopicForRetryable bean if there is also a NewTopic with the same topic name.
270
+ /**
271
+ * Return a collection of {@link NewTopic}s to create or modify. The default
272
+ * implementation retrieves all {@link NewTopic} beans in the application context and
273
+ * applies the {@link #setCreateOrModifyTopic(Predicate)} predicate to each one. It
274
+ * also removes any {@link TopicForRetryable} bean if there is also a NewTopic with
275
+ * the same topic name. This is performed before calling the predicate.
276
+ * @return the collection of {@link NewTopic}s.
277
+ * @since 2.9.10
278
+ * @see #setCreateOrModifyTopic(Predicate)
243
279
*/
244
- private Collection <NewTopic > newTopics () {
280
+ protected Collection <NewTopic > newTopics () {
245
281
Map <String , NewTopic > newTopicsMap = new HashMap <>(
246
282
this .applicationContext .getBeansOfType (NewTopic .class , false , false ));
247
283
Map <String , NewTopics > wrappers = this .applicationContext .getBeansOfType (NewTopics .class , false , false );
@@ -269,6 +305,13 @@ private Collection<NewTopic> newTopics() {
269
305
newTopicsMap .remove (entry .getKey ());
270
306
}
271
307
}
308
+ Iterator <Entry <String , NewTopic >> iterator = newTopicsMap .entrySet ().iterator ();
309
+ while (iterator .hasNext ()) {
310
+ Entry <String , NewTopic > next = iterator .next ();
311
+ if (!this .createOrModifyTopic .test (next .getValue ())) {
312
+ iterator .remove ();
313
+ }
314
+ }
272
315
return new ArrayList <>(newTopicsMap .values ());
273
316
}
274
317
0 commit comments