Skip to content

Commit b82882b

Browse files
committed
Add Java configuration for control-bus sample
Introduce Java-based Spring Integration configuration as an alternative to the existing XML configuration. The new ControlBusConfiguration class uses `@Configuration` and Integration DSL to define the control bus flow and inbound adapter. The application.properties file sets `java-config` as the default profile, allowing users to run the sample with Java configuration out of the box. The XML configuration remains available by explicitly activating the `xml-config` profile.
1 parent 071d683 commit b82882b

File tree

5 files changed

+186
-14
lines changed

5 files changed

+186
-14
lines changed

basic/control-bus/README.md

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,44 @@
11
Control Bus Sample
22
==================
33

4-
This example demonstrates the functionality of the Control Bus component available with Spring Integration. The Control Bus uses SpEL to send a Control Message to start/stop an inbound adapter. To run the Control Bus sample simply execute **ControlBusDemoTest** in the **org.springframework.integration.samples.controlbus** package.
4+
This example demonstrates the functionality of the Control Bus component available with Spring Integration. The Control Bus uses SpEL to send a Control Message to start/stop an inbound adapter.
55

6-
You will see output similar to this:
6+
This sample supports both **XML-based** and **Java-based** Spring Integration configurations. You can select which configuration to use by setting the active Spring profile.
7+
8+
## Configuration Options
9+
10+
This sample supports two configuration modes:
11+
12+
* **Java Configuration** (`java-config` profile) - Uses Java `@Configuration` classes from the `config` package. This is the **default** mode.
13+
* **XML Configuration** (`xml-config` profile) - Uses XML configuration files from `META-INF/spring/integration/`
14+
15+
### Profile Selection
16+
17+
Only one configuration profile should be active at a time. The `java-config` and `xml-config` profiles are mutually exclusive.
18+
19+
* If no profile is explicitly provided, `java-config` is used by default (as configured in `application.properties`).
20+
* To use XML configuration, explicitly activate the `xml-config` profile at runtime.
21+
22+
## Running the Sample
723

8-
INFO : org.springframework.integration.samples.jmx.ControlBusDemo - Received before adapter started: null
9-
INFO : org.springframework.integration.samples.jmx.ControlBusDemo - Received before adapter started: [Payload=Hello][Headers={timestamp=1294950897714, id=240e72fb-93b0-4d38-8fe8-b701cf7e9a5d}]
10-
INFO : org.springframework.integration.samples.jmx.ControlBusDemo - Received after adapter stopped: null
24+
### Using Java Configuration (Default)
25+
26+
The sample uses Java configuration by default. Execute **ControlBusDemoTest** in the **org.springframework.integration.samples.controlbus** package. The test method `demoControlBusWithJavaConfig()` demonstrates the Java configuration mode.
27+
28+
In this mode, the application context is defined using Spring Integration Java configuration classes instead of XML. The configuration classes are located in the `org.springframework.integration.samples.controlbus.config` package.
29+
30+
### Using XML Configuration
31+
32+
To run the sample with XML configuration, activate the `xml-config` profile. The test method `demoControlBusWithXmlConfig()` demonstrates this mode.
33+
34+
This mode uses the legacy XML-based wiring from `ControlBusDemo-context.xml`. The XML namespace is only active when the `xml-config` profile is enabled.
35+
36+
## Expected Output
37+
38+
You will see output similar to this:
1139

40+
```
41+
INFO : org.springframework.integration.samples.controlbus.ControlBusDemoTest - Received before adapter started: null
42+
INFO : org.springframework.integration.samples.controlbus.ControlBusDemoTest - Received before adapter started: [Payload=Hello][Headers={timestamp=1294950897714, id=240e72fb-93b0-4d38-8fe8-b701cf7e9a5d}]
43+
INFO : org.springframework.integration.samples.controlbus.ControlBusDemoTest - Received after adapter stopped: null
44+
```
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2025-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.integration.samples.controlbus.config;
17+
18+
import org.springframework.beans.factory.annotation.Qualifier;
19+
import org.springframework.context.annotation.Bean;
20+
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.context.annotation.Profile;
22+
import org.springframework.integration.channel.DirectChannel;
23+
import org.springframework.integration.channel.QueueChannel;
24+
import org.springframework.integration.config.EnableIntegration;
25+
import org.springframework.integration.dsl.IntegrationFlow;
26+
import org.springframework.integration.dsl.Pollers;
27+
import org.springframework.messaging.MessageChannel;
28+
29+
/**
30+
* Java-based Spring Integration configuration for the Control Bus sample.
31+
* <p>
32+
* This configuration demonstrates the Control Bus component functionality,
33+
* which uses SpEL expressions to control Spring Integration endpoints
34+
* (e.g., start/stop an inbound adapter).
35+
* <p>
36+
* Activate this configuration using the "java-config" profile.
37+
* <p>
38+
* This configuration is functionally equivalent to {@code ControlBusDemo-context.xml}
39+
* and defines:
40+
* <ul>
41+
* <li>A control channel for sending control messages</li>
42+
* <li>An output channel (queue-based) for the inbound adapter</li>
43+
* <li>A control bus endpoint that processes control messages</li>
44+
* <li>An inbound channel adapter that generates "Hello" messages at a fixed rate</li>
45+
* </ul>
46+
*
47+
* @author Glenn Renfro
48+
*/
49+
@Configuration
50+
@EnableIntegration
51+
@Profile("java-config")
52+
public class ControlBusConfiguration {
53+
54+
/**
55+
* Create a direct channel for sending control messages to the control bus.
56+
* <p>
57+
* This channel is used to send SpEL expressions that control Spring Integration
58+
* endpoints (e.g., {@code @inboundAdapter.start()} or {@code @inboundAdapter.stop()}).
59+
*
60+
* @return a DirectChannel for control messages
61+
*/
62+
@Bean
63+
public MessageChannel controlChannel() {
64+
return new DirectChannel();
65+
}
66+
67+
/**
68+
* Create a queue-based channel for receiving messages from the inbound adapter.
69+
* <p>
70+
* This channel uses a queue to allow asynchronous message consumption.
71+
*
72+
* @return a QueueChannel for adapter output
73+
*/
74+
@Bean
75+
public MessageChannel adapterOutputChannel() {
76+
return new QueueChannel();
77+
}
78+
79+
/**
80+
* Create an integration flow that connects the control channel to the control bus.
81+
* <p>
82+
* Messages sent to the control channel are processed by the control bus,
83+
* which evaluates SpEL expressions to control Spring Integration endpoints.
84+
*
85+
* @param controlChannel input channel for control commands
86+
* @return an IntegrationFlow connecting controlChannel to controlBus
87+
*/
88+
@Bean
89+
public IntegrationFlow controlBusFlow(@Qualifier("controlChannel") MessageChannel controlChannel) {
90+
return IntegrationFlow.from(controlChannel)
91+
.controlBus()
92+
.get();
93+
}
94+
95+
/**
96+
* Create an inbound channel adapter that generates messages.
97+
* <p>
98+
* The adapter:
99+
* <ul>
100+
* <li>Generates the string "Hello" as the payload</li>
101+
* <li>Sends messages to the adapterOutputChannel</li>
102+
* <li>Starts with auto-startup disabled (must be started via control bus)</li>
103+
* <li>Polls at a fixed rate of 1000ms</li>
104+
* </ul>
105+
*
106+
* @return an IntegrationFlow representing the inbound adapter
107+
*/
108+
@Bean
109+
public IntegrationFlow inboundAdapter() {
110+
return IntegrationFlow.fromSupplier(() -> "Hello",
111+
c -> c.id("inboundAdapter")
112+
.autoStartup(false)
113+
.poller(Pollers.fixedRate(1000)))
114+
.channel(adapterOutputChannel())
115+
.get();
116+
}
117+
118+
}
119+

basic/control-bus/src/main/resources/META-INF/spring/integration/ControlBusDemo-context.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77

88
<int:channel id="controlChannel"/>
99

10-
<int:channel id="adapterOutputChanel">
10+
<int:channel id="adapterOutputChannel">
1111
<int:queue/>
1212
</int:channel>
1313

1414
<int:control-bus input-channel="controlChannel"/>
1515

1616
<int:inbound-channel-adapter id="inboundAdapter"
17-
channel="adapterOutputChanel"
17+
channel="adapterOutputChannel"
1818
expression="'Hello'"
1919
auto-startup="false">
2020
<int:poller fixed-rate="1000"/>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
spring.profiles.active=java-config
2+

basic/control-bus/src/test/java/org/springframework/integration/samples/controlbus/ControlBusDemoTest.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2017-present the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,31 +20,49 @@
2020
import org.junit.jupiter.api.Test;
2121

2222
import org.springframework.context.ConfigurableApplicationContext;
23+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2324
import org.springframework.context.support.ClassPathXmlApplicationContext;
25+
import org.springframework.core.env.StandardEnvironment;
2426
import org.springframework.messaging.MessageChannel;
2527
import org.springframework.messaging.PollableChannel;
2628
import org.springframework.messaging.support.GenericMessage;
2729

2830
/**
2931
* @author Oleg Zhurakousky
3032
* @author Gary Russell
33+
* @author Glenn Renfro
3134
*
3235
*/
3336
public class ControlBusDemoTest {
3437

3538
private static Log logger = LogFactory.getLog(ControlBusDemoTest.class);
3639

3740
@Test
38-
public void demoControlBus(){
41+
public void demoControlBusWithJavaConfig() {
42+
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
43+
ac.setEnvironment(new StandardEnvironment());
44+
ac.getEnvironment().setActiveProfiles("java-config");
45+
ac.scan("org.springframework.integration.samples.controlbus.config");
46+
ac.refresh();
47+
runControlBusDemo(ac);
48+
ac.close();
49+
}
50+
51+
@Test
52+
public void demoControlBusWithXmlConfig() {
3953
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext(
4054
"/META-INF/spring/integration/ControlBusDemo-context.xml");
55+
runControlBusDemo(ac);
56+
ac.close();
57+
}
58+
59+
private void runControlBusDemo(ConfigurableApplicationContext ac) {
4160
MessageChannel controlChannel = ac.getBean("controlChannel", MessageChannel.class);
42-
PollableChannel adapterOutputChanel = ac.getBean("adapterOutputChanel", PollableChannel.class);
43-
logger.info("Received before adapter started: " + adapterOutputChanel.receive(1000));
61+
PollableChannel adapterOutputChannel = ac.getBean("adapterOutputChannel", PollableChannel.class);
62+
logger.info("Received before adapter started: " + adapterOutputChannel.receive(1000));
4463
controlChannel.send(new GenericMessage<String>("@inboundAdapter.start()"));
45-
logger.info("Received before adapter started: " + adapterOutputChanel.receive(1000));
64+
logger.info("Received before adapter started: " + adapterOutputChannel.receive(1000));
4665
controlChannel.send(new GenericMessage<String>("@inboundAdapter.stop()"));
47-
logger.info("Received after adapter stopped: " + adapterOutputChanel.receive(1000));
48-
ac.close();
66+
logger.info("Received after adapter stopped: " + adapterOutputChannel.receive(1000));
4967
}
5068
}

0 commit comments

Comments
 (0)