是否可以使用BeanFactory从不同的属性值创建集成流程bean?

时间:2018-03-08 08:36:09

标签: java spring spring-integration spring-integration-dsl

我的目的是从各种源/目录创建IntegrationFlow bean实例(首先,可能来自ftp)。因此,在application.properties我想定义类似的东西,入站目录的数量可能会有所不同:

inbound.file.readPath[0]=source1
inbound.file.processedPath[0]=processed1
inbound.file.failedPath[0]=failed1

inbound.file.readPath[1]=source2
inbound.file.processedPath[1]=processed2
inbound.file.failedPath[1]=failed2

我还想维护源的来源(通过标头扩充),因此不能将所有文件放在spring之外的一个目录中。

拥有FilePollingFlow是否可以从上面提到的属性创建这些bean实例?我可以想象这样的东西,但我不知道如何将属性传递给bean实例和如何参考指数:

@Configuration
public class FilePollingIntegrationFlow extends AbstractFactoryBean<IntegrationFlow> {

    @Autowired
    private FilePollingConfiguration config;

    @Override
    public Class<IntegrationFlow> getObjectType() {
        return IntegrationFlow.class;
    }

    @Override
    protected IntegrationFlow createInstance() throws Exception {
      return IntegrationFlows
                .from(s -> /* FIXME config.getReadPath()? instead of inboundReadDirectory, but how to handle indices? */s.file(inboundReadDirectory).preventDuplicates(true).scanEachPoll(true).patternFilter("*.txt"),
                        e -> e.poller(Pollers.fixedDelay(inboundPollingPeriod)
                                .taskExecutor(taskExecutor())
                                .transactionSynchronizationFactory(transactionSynchronizationFactory())
                                .transactional(transactionManager())))
                .log(LoggingHandler.Level.INFO, getClass().getName(), "'Read inbound file: ' .concat(payload)")
                .enrichHeaders(m -> m.headerExpression(FileHeaders.ORIGINAL_FILE, "payload"))
                .transform(Transformers.fileToString())
                .channel(ApplicationConfiguration.FILE_INBOUND_CHANNEL)
                .get();
   }
}
@Component
@ConfigurationProperties("inbound")
public class FilePollingConfiguration {

private List<File> files = new ArrayList<>();

public static class File {
    private String readPath;
    private String processedPath;
    private String failedPath;

    public String getReadPath() {
        return readPath;
    }

    public void setReadPath(String readPath) {
        this.readPath = readPath;
    }

    public String getProcessedPath() {
        return processedPath;
    }

    public void setProcessedPath(String processedPath) {
        this.processedPath = processedPath;
    }

    public String getFailedPath() {
        return failedPath;
    }

    public void setFailedPath(String failedPath) {
        this.failedPath = failedPath;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("readPath", readPath)
                .append("processedPath", processedPath)
                .append("failedPath", failedPath)
                .toString();
    }


    public List<File> getFiles() {
        return files;
    }

    public void setFiles(List<File> files) {
        this.files = files;
    }
}

1 个答案:

答案 0 :(得分:1)

对于几个类似的流程,Framework为您提供了IntegrationFlowContexthttps://docs.spring.io/spring-integration/docs/5.0.3.RELEASE/reference/html/java-dsl.html#java-dsl-runtime-flows等解决方案。因此,您需要的只是对这些文件和创建流程的迭代及其注册。

关于类似于内部File的类似属性的列表,您应该修改Spring Boot中的建议:https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-external-config-yaml

注意那里的servers财产。我的意思是如果你在Java类中调用它files,那么在属性文件中必须是files

<强>更新

这就是我的工作方式:

我的application.properties

my.source.dirs=/tmp/in1,/tmp/in2

应用程序是这样的:

@SpringBootApplication
public class So49168720Application {

    public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(So49168720Application.class, args);

        File file1 = new File("/tmp/in1", "foo.txt");
        file1.createNewFile();
        FileCopyUtils.copy("FOO".getBytes(), file1);

        File file2 = new File("/tmp/in2", "bar.txt");
        file2.createNewFile();
        FileCopyUtils.copy("BAR".getBytes(), file2);


        PollableChannel resultChannel = applicationContext.getBean("resultChannel", PollableChannel.class);

        System.out.println(resultChannel.receive(10000));
        System.out.println(resultChannel.receive(10000));

        file1.delete();
        file2.delete();
    }

    @Value("${my.source.dirs}")
    private String[] sourceDirs;

    @Autowired
    private IntegrationFlowContext flowContext;


    @PostConstruct
    private void registerFilePollingFlows() {
        Arrays.asList(this.sourceDirs).forEach(inboundSource -> {
            IntegrationFlow flow =
                    IntegrationFlows
                            .from(Files.inboundAdapter(new File(inboundSource))
                                    .patternFilter("*.txt"))
                            .log(LoggingHandler.Level.INFO, getClass().getName(),
                                    "'Read inbound file: ' .concat(payload)")
                            .transform(Files.toStringTransformer())
                            .channel(resultChannel())
                            .get();

            this.flowContext.registration(flow).register();
        });
    }

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerSpec defaultPoller() {
        return Pollers.fixedDelay(1000);
    }

    @Bean
    public PollableChannel resultChannel() {
        return new QueueChannel();
    }

}

我在日志中记录了这些消息:

2018-03-13 17:43:05.148  INFO 19676 --- [ask-scheduler-3] ication$$EnhancerBySpringCGLIB$$4fda2b12 : Read inbound file: \tmp\in2\bar.txt
2018-03-13 17:43:05.148  INFO 19676 --- [ask-scheduler-2] ication$$EnhancerBySpringCGLIB$$4fda2b12 : Read inbound file: \tmp\in1\foo.txt
GenericMessage [payload=BAR, headers={file_originalFile=\tmp\in2\bar.txt, id=4a692a68-3871-b708-a28e-c4dc378de7e5, file_name=bar.txt, file_relativePath=bar.txt, timestamp=1520977385150}]
GenericMessage [payload=FOO, headers={file_originalFile=\tmp\in1\foo.txt, id=32597359-6602-3df6-5f6f-dac2f4ad788f, file_name=foo.txt, file_relativePath=foo.txt, timestamp=1520977385150}]

但是,这已经基于Spring Integration 5.0和Spring Boot 2.0。有什么理由不升级你的项目吗?