As explained in previous post Spring Integration application can run inside any spring application container. It may be a web application (loading context via web.xml) or a standalone application (loading context via ClassPathXmlApplicationContext.class).
We will start with a quick file watcher example in which we will implement a file adaptor which will process incoming files asynchronously.
We will run the application as a Java application using main() function and ClassPathXmlApplicationContext.class
Our project will have following structure:
We will start with a quick file watcher example in which we will implement a file adaptor which will process incoming files asynchronously.
We will run the application as a Java application using main() function and ClassPathXmlApplicationContext.class
Our project will have following structure:
Getting Started
- Create a maven project with structure as shown in figure above, with following pom.xml (note Spring Integration dependencies)
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.anishsneh.spring.integration</groupId> <artifactId>spring-integration-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Spring Integration - File Watcher</name> <description>Spring Integration - File Watcher</description> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-core</artifactId> <version>2.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-file</artifactId> <version>2.2.4.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.2.3.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> </project>
-
Create application-context.xml file as give below:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:int-file="http://www.springframework.org/schema/integration/file" xmlns:int="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd"> <int:channel id="fileInputChannel"></int:channel> <int:channel id="fileProcessChannel"></int:channel> <int:channel id="fileOutputChannel"></int:channel> <int-file:inbound-channel-adapter channel="fileInputChannel" directory="/home/anishsneh/tmp/input" filename-regex="demo_file_[0-9]{4}.txt" id="fileInputAdaptor"> <int:poller default="true" fixed-delay="5000" id="filePoller"></int:poller> </int-file:inbound-channel-adapter> <int-file:outbound-channel-adapter channel="fileOutputChannel" directory="/home/anishsneh/tmp/output" filename-generator="customFileNameGeneratorBean" id="fileOutputAdaptor"></int-file:outbound-channel-adapter> <int-file:file-to-string-transformer input-channel="fileInputChannel" output-channel="fileProcessChannel"></int-file:file-to-string-transformer> <int:service-activator id="printServiceActivator" input-channel="fileProcessChannel" method="processContent" output-channel="fileOutputChannel" ref="printServiceActivatorBean"></int:service-activator> <beans:bean class="com.anishsneh.spring.integration.PrintServiceActivator" id="printServiceActivatorBean"></beans:bean> <beans:bean class="com.anishsneh.spring.integration.CustomFileNameGenerator" id="customFileNameGeneratorBean"></beans:bean> </beans:beans>
-
Create following Java classes:
- com.anishsneh.spring.integration.Main
- com.anishsneh.spring.integration.PrintServiceActivator
- com.anishsneh.spring.integration.CustomFileNameGenerator
com.anishsneh.spring.integration.Main
package com.anishsneh.spring.integration; import org.apache.log4j.Logger; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { private static final Logger logger = Logger.getLogger(Main.class); public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/META-INF/spring/application-context.xml"); logger.debug("Context intialized: " + context); } }
com.anishsneh.spring.integration.PrintServiceActivator
package com.anishsneh.spring.integration; import org.apache.log4j.Logger; public class PrintServiceActivator { private static final Logger logger = Logger.getLogger(PrintServiceActivator.class); public String processContent(String fileContent){ logger.debug(fileContent); return fileContent; } }
com.anishsneh.spring.integration.CustomFileNameGenerator
package com.anishsneh.spring.integration; import org.springframework.integration.Message; import org.springframework.integration.file.DefaultFileNameGenerator; public class CustomFileNameGenerator extends DefaultFileNameGenerator { @Override public String generateFileName(Message message) { String originalFileName = super.generateFileName(message); String newFileName = "updated_" + originalFileName; return newFileName; } }
- Create minimal log4j.xml file
- Run com.anishsneh.spring.integration.Main, it will load the application context and start adapter. We will see the following flow:
- Adapter starts listening to the input directory configured, it polls the directory on fixed intervals (as provided by poller configuration)
- It picks up all the files whose name starts with the pattern given in file name pattern (if the file with required pattern is available in the directory). We may also copy some text file with the matching pattern to see the realtime working
- It delivers the files to file input channel configured for further processing
- File to string transformer takes the file from input channel (since it is the next step in the flow) and transform into text. Then it delivers the contents to output channel (i.e. file process channel) configured for further processing
- File process channel gives the message to next component i.e. service activator, where it executes processContent() method on the extracted contents (in our example we are just printing the contents)
- After processing/printing service activator gives the returned value (as per method's logic) to the output channel; which in-turn is consumed by file output channel
- File outbound adapter takes the message from service activator and saves the message into the directory configured for output (file names for the output files are generated by CustomFileNameGenerator class)
Also in the flow output of one step is used as input by the next step (and so on), which evolves in the form of a pipeline processing.