问题
I have a Spring integration flow as following.
<int-file:inbound-channel-adapter id="filesIn"
directory="file:${incomingDir}"
filename-pattern="*.txt"
prevent-duplicates="true">
<int:poller id="poller" fixed-delay="5000"/>
</int-file:inbound-channel-adapter>
<int:splitter input-channel="filesIn"
ref="filesSplitterService"
method="splitFilesToReportContent"
output-channel="reportProcessIn"
/>
<int:channel id="reportProcessIn"/>
<int:chain input-channel="reportProcessIn" output-channel="reportProcessOut">
<int:service-activator ref="reportProcessorService" method="readReportMetaData" />
<int:service-activator ref="reportProcessorService" method="saveReportFileInFileSystem" />
<int:service-activator ref="reportProcessorService" method="saveReportMetaDataInDB" />
</int:chain>
<int:channel id="reportProcessOut"/>
<bean id="filesSplitterService" class="com.app.integration.FilesSplitter"/>
<bean id="reportProcessorService" class="com.app.reporting.integration.ReportProcessor"/>
Incoming file is splitted by one service and make a List of ReportContent.
Then service chain takes each element of the ReportContent and works on them to read_report_meta_data from the file content (like report id, report type), save report content string to a file in the appropriate directory, and save report meta data in a database. The flow is working fine except there seems to have a loose end.
I get the following exception.
org.springframework.integration.MessageDeliveryException: Dispatcher has no subscribers
I don't need to aggregate the splitted elements. Flow is completed as far as I am concerned after saving meta data in the database.
However I would like to move the original file, the master file I splitted into report files, to some other directory after working with it. How could I incorporate that logic? File:outbound-channel seems to be the way to do it, but I don't understand how to.
Is there a way to avoid saveReportFileInSystem and saveReportMetaDataInDB operations based on some meta-data read in readReportMetaData operation.
For convenience, I have given below the structure of my service classes.
class : FilesSplitter
public List<ReportContent> splitFilesToReportContent(File file){
}
class : ReportProcessor
public ReportContent readReportMetaData(ReportContent reportContent) {
}
public ReportContent saveReportFileInFileSystem(ReportContent reportContent) {
}
public ReportContent saveReportMetaDataInDB(ReportContent reportContent) {
}
One thing to note is that I am not using message headers. I didn't yet feel the necessity to use to but I am okay to use. I am new to spring integration so, any advice to improve this flow would be helpful.
回答1:
1. I get the following exception... org.springframework.integration.MessageDeliveryException
I suppose you have missed file:outbound-channel-adapter
definition here.
2. However I would like to move the original file, the master file I splitted into report files, to some other directory after working with it. How could I incorporate that logic?
As written in 14.3.4 File Outbound Channel Adapter your should use delete-source-files
attribute for outbound-channel-adapter
but(!)
...attribute will only have an effect if the inbound Message has a File payload or if the FileHeaders.ORIGINAL_FILE header value contains either the source File instance or a String representing the original file path.
So, in you reportProcessorService
you should deal with raw messages anyway. You don't have source file as a payload anymore. Thus, only one option is to set properly FileHeaders.ORIGINAL_FILE
header value.
3. Is there a way to avoid saveReportFileInSystem and saveReportMetaDataInDB operations based on some meta-data read in readReportMetaData operation?
Yes, there is. Use after readReportMetaData
in the chain EIP either PayloadTypeRouter (if it's possible becorse its simple) or Configuring (Generic) Router
回答2:
We usually have Dispatcher has no subscribers
when there is really no subscribers for the SubscribableChannel
(like yours reportProcessOut
) or those subscribers has been stopped, which can treat as a "no subscribers", too.
We usually recommend to the send the <service-activator>
result to the nullChannel
, if you aren't interested in that result. That is the case when you can't achieve your task with just standard one-way component - <outbound-channel-adapter>
.
However I would like to move the original file, the master file I splitted into report files,
You can do that with the second one-way subscriber for the <publish-subscriber-channel>
as a filesIn
. And achiever that with standard File.renameTo()
function. I don't reason to blow your mind with something like <int-file:outbound-channel-adapter>
. You are on the file system already. So, just use its capabilities. We need adapters for files, when we deal with remote files like FTP, SFTP.
You can use Map<String, Object> headers
as a second parameter for your 3service methods and Framework will inject the proper object for you from the request Message<?>
.
See @Andriy Kryvtsun 's answer regarding "avoid saveReportFileInSystem".
As an alternative you can use the <filter>
to skip and drop messages which should not be saved by some reason.
来源:https://stackoverflow.com/questions/35775105/spring-integration-inbound-file-endpoint-how-to-process-a-file-correctly