Skip to content

Commit 412b46b

Browse files
Jay Bryantartembilan
authored andcommitted
Use the Spring Initializr
I edited the document and modified the code (mostly changing package names) to use the Spring Initializr. * Fixing broken links how_to_complete_this_guide.adoc includes links to anchors called `scratch` and ` internal`. I'm making sure those anchors exist. Sometimes, that requires rearran ging content. * Upgraded to Spring Boot 2.2 I upgraded the build files to Spring Boot 2.2.0, which necessitated changing the tests to work with JUnit 5 and upgrading the Gradle wrappers.
1 parent 4a5ea6b commit 412b46b

File tree

23 files changed

+608
-441
lines changed

23 files changed

+608
-441
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
*.DS_Store
12
*.sw?
23
.#*
34
*#

README.adoc

Lines changed: 155 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,122 +10,225 @@
1010
:icons: font
1111
:source-highlighter: prettify
1212
:project_id: gs-integration
13-
This guide walks you through the process of using Spring Integration to create a simple application that retrieves data from an RSS Feed (Spring Blog), manipulates the data, and then writes it to a file. This guide uses traditional Spring Integration XML configuration; other guides exist showing the use of JavaConfig/DSL with and without JDK 8 Lambda expressions.
1413

15-
== What you'll build
14+
This guide walks you through the process of using Spring Integration to create a simple
15+
application that retrieves data from an RSS Feed (Spring Blog), manipulates the data, and
16+
then writes it to a file. This guide uses traditional Spring Integration XML
17+
configuration. Other guides show how to use Java Configuration and DSL with and without
18+
JDK 8 Lambda expressions.
1619

17-
You'll create a flow with Spring Integration using traditional XML configuration.
20+
== What You Will Build
1821

19-
== What you'll need
22+
You will create a flow with Spring Integration by using traditional XML configuration.
23+
24+
== What You Need
2025

2126
:java_version: 1.8
2227
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/prereq_editor_jdk_buildtools.adoc[]
2328

2429
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/how_to_complete_this_guide.adoc[]
2530

26-
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/hide-show-gradle.adoc[]
31+
[[scratch]]
32+
== Starting with Spring Initializr
2733

28-
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/hide-show-maven.adoc[]
34+
For all Spring applications, you should start with the https://start.spring.io[Spring
35+
Initializr]. The Initializr offers a fast way to pull in all the dependencies you need for
36+
an application and does a lot of the set up for you. This example needs only the Spring
37+
Integration dependency. The following image shows the Initializr set up for this sample
38+
project:
2939

30-
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/hide-show-sts.adoc[]
40+
image::images/initializr.png[]
3141

42+
NOTE: The preceding image shows the Initializr with Maven chosen as the build tool. You
43+
can also use Gradle. It also shows values of `com.example` and `integration` as the Group
44+
and Artifact, respectively. You will use those values throughout the rest of this sample.
3245

33-
[[initial]]
34-
== Define an integration flow
46+
The following listing shows the `pom.xml` file that is created when you choose Maven:
47+
48+
====
49+
[src,xml]
50+
----
51+
include::initial/pom.xml[]
52+
----
53+
====
3554

36-
For this guide's sample application, you will define a Spring Integration flow that reads blog posts from Spring IO's RSS feed, transforms them into an easily readable `String` consisting of the post title and the URL for the post, and appends that `String` to the end of a file `/tmp/si/SpringBlog`.
55+
The following listing shows the `build.gradle` file that is created when you choose Gradle:
3756

38-
To define an integration flow, you simply create a Spring XML configuration with a handful of elements from Spring Integration's XML namespaces. Specifically, for the desired integration flow, you work with elements from these Spring Integration namespaces: core, feed, and file.
57+
====
58+
[src,java]
59+
----
60+
include::initial/build.gradle[]
61+
----
62+
====
3963

40-
The following XML configuration file defines the integration flow:
64+
== Add to the Build Files
4165

42-
`src/main/resources/hello/integration.xml`
43-
[source,xml]
66+
For this example, you need to add two dependencies:
67+
68+
* `spring-integration-feed`
69+
* `spring-integration-file`
70+
71+
The following listing shows the final `pom.xml` file:
72+
73+
====
74+
[src,xml]
4475
----
45-
include::complete/src/main/resources/hello/integration.xml[]
76+
include::complete/pom.xml[]
4677
----
78+
====
4779

48-
As you can see, three integration elements are in play here:
80+
The following listing shows the final `build.gradle` file:
4981

50-
* `<feed:inbound-channel-adapter>`. An inbound adapter that retrieves the posts, one per poll. As configured here, it polls every 5 seconds. The posts are placed into a channel named "news" (corresponding with the adapter's ID).
51-
* `<int:transformer>`. Transforms entries (`com.rometools.rome.feed.synd.SyndEntry`) in the "news" channel, extracting the entry's title (`payload.title`) and link (`payload.link`) and concatenating them into a readable `String` (adding a newline). The `String` is then sent to the output channel named "file".
52-
* `<file:outbound-channel-adapter>`. An outbound channel adapter that writes content from its channel (here named "file") to a file. Specifically, as configured here, it will append anything in the "file" channel to a file at `/tmp/si/SpringBlog`.
82+
====
83+
[src,java]
84+
----
85+
include::complete/build.gradle[]
86+
----
87+
====
5388

54-
This simple flow is illustrated like this:
89+
[[initial]]
90+
== Define an Integration Flow
5591

56-
image::images/blogToFile.png[A flow that reads RSS feed entries, transforms them to a String, and appends them to a file.]
92+
For this guide's sample application, you will define a Spring Integration flow that:
5793

58-
Ignore the `auto-startup` attribute for now; we'll revisit that later when discussing testing; just notice that it will be `true` by default which means the posts will be fetched when the application starts.
59-
Also note the property placeholder in the `filename-generator-expression`; this means the default will be `SpringBlog` but can be overridden with a property
94+
* Reads blog posts from the RSS feed at spring.io.
95+
* Transforms them into an easily readable `String` consisting of the post title and the URL for the post.
96+
* Appends that `String` to the end of a file (`/tmp/si/SpringBlog`).
6097

61-
== Make the application executable
98+
To define an integration flow, you can create a Spring XML configuration with a handful of
99+
elements from Spring Integration's XML namespaces. Specifically, for the desired
100+
integration flow, you work with elements from these Spring Integration namespaces: core,
101+
feed, and file. (Getting the last two is why we had to modify the build files provided by
102+
the Spring Initializr.)
62103

63-
Although it is common to configure a Spring Integration flow within a larger application, perhaps even a web application, there's no reason that it can't be defined in a simpler standalone application.
64-
That's what you do next, creating a main class that kicks off the integration flow and also declares a handful of beans to support the integration flow. You also build the application into a standalone executable JAR file.
65-
We use Spring Boot's `SpringApplication` to create the application context.
66-
Since this guide uses an the XML namespace for the integration flow, notice that we use `@ImportResource` to load it into the application context.
104+
The following XML configuration file (from
105+
`src/main/resources/integration/integration.xml`) defines the integration flow:
67106

107+
====
108+
[source,xml]
109+
----
110+
include::complete/src/main/resources/integration/integration.xml[]
111+
----
112+
====
113+
114+
Three integration elements are in play here:
115+
116+
* `<feed:inbound-channel-adapter>`: An inbound adapter that retrieves the posts, one per
117+
poll. As configured here, it polls every five seconds. The posts are placed into a channel
118+
named `news` (corresponding to the adapter's ID).
119+
* `<int:transformer>`: Transforms entries (`com.rometools.rome.feed.synd.SyndEntry`) in
120+
the `news` channel, extracting the entry's title (`payload.title`) and link
121+
(`payload.link`) and concatenating them into a readable `String` (and adding a newline).
122+
The `String` is then sent to the output channel named `file`.
123+
* `<file:outbound-channel-adapter>`: An outbound channel adapter that writes content from
124+
its channel (named `file`) to a file. Specifically, as configured here, it appends
125+
anything in the `file` channel to a file at `/tmp/si/SpringBlog`.
126+
127+
The following image shows this simple flow:
128+
129+
image::images/blogToFile.png[A flow that reads RSS feed entries, transforms them to a String, and appends them to a file.]
68130

69-
`src/main/java/hello/Application.java`
131+
Ignore the `auto-startup` attribute for now. We revisit that later when we discuss
132+
testing. For now, notice that it is, by default, `true`, which means the posts are fetched
133+
when the application starts. Also note the property placeholder in the
134+
`filename-generator-expression`. It means that the default is `SpringBlog` but can be
135+
overridden with a property.
136+
137+
== Make the Application Executable
138+
139+
Although it is common to configure a Spring Integration flow within a larger application
140+
(perhaps even a web application), there is no reason that it cannot be defined in a
141+
simpler standalone application. That is what you will do next: Create a main class that
142+
kicks off the integration flow and that declares a handful of beans to support the
143+
integration flow. You will also build the application into a standalone executable JAR
144+
file. We use Spring Boot's `@SpringBootApplication` annotation to create the application
145+
context. Since this guide uses the XML namespace for the integration flow, you must use
146+
the `@ImportResource` annotation to load it into the application context. The following
147+
listing (from `src/main/java/com/example/integration/IntegrationApplication.java`) shows
148+
the application file:
149+
150+
====
70151
[source,java]
71152
----
72-
include::complete/src/main/java/hello/Application.java[]
153+
include::complete/src/main/java/com/example/integration/IntegrationApplication.java[]
73154
----
155+
====
74156

75157
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/build_an_executable_jar_subhead.adoc[]
76158
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/build_an_executable_jar_with_both.adoc[]
77159

78160
[[run]]
79161
== Run the application
80162

81-
Now you can run the application from the jar:
82-
....
163+
Now you can run the application from the jar by running the following command:
164+
165+
====
166+
[source,bash]
167+
----
83168
java -jar build/libs/{project_id}-0.1.0.jar
84169
85170
... app starts up ...
86-
....
171+
----
172+
====
87173

88-
Once the application starts up, it connects to the RSS feed and starts fetching blog posts. The application processes those posts through the integration flow you defined, ultimately appending the post information to a file at `/tmp/si/SpringBlog`.
174+
Once the application starts, it connects to the RSS feed and starts fetching blog posts.
175+
The application processes those posts through the integration flow you defined, ultimately
176+
appending the post information to a file at `/tmp/si/SpringBlog`.
89177

90-
After the application has been running for awhile, you should be able to view the file at `/tmp/si/SpringBlog` to see the data from a handful of posts. On a UNIX-based operating system, you can also choose to tail the file to see the results as they are written:
178+
After the application has been running for awhile, you should be able to view the file at
179+
`/tmp/si/SpringBlog` to see the data from a handful of posts. On a UNIX-based operating
180+
system, you can also `tail` the file to see the results, as they are written, by running
181+
the following command:
91182

183+
====
184+
[source,bash]
92185
----
93186
tail -f /tmp/si/SpringBlog
94187
----
188+
====
95189

96-
You should see something like this (the actual news will differ):
190+
You should see something like the following sample output (though the actual news will
191+
differ):
97192

98-
....
193+
====
194+
[source,bash]
195+
----
99196
Spring Integration Java DSL 1.0 GA Released @ https://spring.io/blog/2014/11/24/spring-integration-java-dsl-1-0-ga-released
100197
This Week in Spring - November 25th, 2014 @ https://spring.io/blog/2014/11/25/this-week-in-spring-november-25th-2014
101198
Spring Integration Java DSL: Line by line tutorial @ https://spring.io/blog/2014/11/25/spring-integration-java-dsl-line-by-line-tutorial
102199
Spring for Apache Hadoop 2.1.0.M2 Released @ https://spring.io/blog/2014/11/14/spring-for-apache-hadoop-2-1-0-m2-released
103-
....
200+
----
201+
====
104202

105203
== Testing
106204

107-
Examine the `complete` project and you will see a test case.
205+
Examine the `complete` project and you will see a test case, in
206+
`src/test/java/com/example/integration/FlowTests.java`:
108207

109-
`src/test/java/hello/FlowTests.java`
208+
====
110209
[source,java]
111210
----
112-
include::complete/src/test/java/hello/FlowTests.java[]
211+
include::complete/src/test/java/com/example/integration/FlowTests.java[]
113212
----
213+
====
114214

115-
This uses Spring Boot's test support to set a property `auto.startup` to `false`.
116-
It is generally not a good idea to rely on a network connection for tests, especially in a CI environment.
117-
So, instead, we prevent the feed adapter from starting and inject a `SyndEntry` into the `news` channel for processing by the rest of the flow.
118-
The test also sets the `feed.file.name` so the test writes to a different file; then:
215+
This test uses Spring Boot's test support to set a property named `auto.startup` to
216+
`false`. It is generally not a good idea to rely on a network connection for tests,
217+
especially in a CI environment. Instead, we prevent the feed adapter from starting and
218+
inject a `SyndEntry` into the `news` channel for processing by the rest of the flow. The
219+
test also sets the `feed.file.name` so that the test writes to a different file. Then it:
119220

120-
- verifies the adapter is stopped
121-
- creates a test `SyndEntry`
122-
- deletes the test output file (if it's present)
123-
- sends the message
124-
- verifies the file exists
125-
- reads the file and verifies that the data is as expected
221+
- Verifies that the adapter is stopped.
222+
- Creates a test `SyndEntry`.
223+
- Deletes the test output file (if it is present).
224+
- Sends the message.
225+
- Verifies that the file exists.
226+
- Reads the file and verifies that the data is as expected.
126227

127228
== Summary
128-
Congratulations! You have developed a simple application that uses Spring Integration to fetch blog posts from spring.io, process them, and write them to a file.
229+
230+
Congratulations! You have developed a simple application that uses Spring Integration to
231+
fetch blog posts from spring.io, process them, and write them to a file.
129232

130233
== See Also
131234

complete/build.gradle

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,27 @@
1-
buildscript {
2-
repositories {
3-
mavenCentral()
4-
}
5-
dependencies {
6-
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
7-
}
1+
plugins {
2+
id 'org.springframework.boot' version '2.2.0.RELEASE'
3+
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
4+
id 'java'
85
}
96

10-
apply plugin: 'java'
11-
apply plugin: 'eclipse'
12-
apply plugin: 'idea'
13-
apply plugin: 'org.springframework.boot'
14-
apply plugin: 'io.spring.dependency-management'
15-
16-
bootJar {
17-
baseName = 'gs-integration'
18-
version = '0.1.0'
19-
}
7+
group = 'com.example'
8+
version = '0.0.1-SNAPSHOT'
9+
sourceCompatibility = '1.8'
2010

2111
repositories {
22-
mavenCentral()
12+
mavenCentral()
2313
}
2414

25-
sourceCompatibility = 1.8
26-
targetCompatibility = 1.8
27-
2815
dependencies {
29-
compile("org.springframework.boot:spring-boot-starter-integration")
30-
compile("org.springframework.integration:spring-integration-feed")
31-
compile("org.springframework.integration:spring-integration-file")
32-
testCompile("org.springframework.boot:spring-boot-starter-test")
33-
testCompile("junit:junit")
34-
}
35-
36-
tasks.withType(JavaExec) {
37-
standardInput = System.in
16+
implementation 'org.springframework.boot:spring-boot-starter-integration'
17+
implementation 'org.springframework.integration:spring-integration-feed'
18+
implementation 'org.springframework.integration:spring-integration-file'
19+
testImplementation('org.springframework.boot:spring-boot-starter-test') {
20+
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
21+
}
22+
testImplementation 'org.springframework.integration:spring-integration-test'
3823
}
3924

40-
41-
eclipse {
42-
project {
43-
natures += 'org.springframework.ide.eclipse.core.springnature'
44-
}
25+
test {
26+
useJUnitPlatform()
4527
}
46-
47-
2.01 KB
Binary file not shown.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
#Thu Mar 01 09:05:42 CST 2018
21
distributionBase=GRADLE_USER_HOME
32
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip

0 commit comments

Comments
 (0)