我有一个用户界面,可以在其中添加或删除保留在postgres DB中的FTP服务器(添加端口和用户名..etc),我的应用程序将使用Spring MVC和Spring Integration读取数据库中的连接对于动态FTP(我正在使用委派会话工厂和旋转建议),应用在运行时正在运行,并读取了数据库中可用的连接,因此将传输我指定的FTP目录中的可用连接。我的问题是,如果我使用该界面删除或添加新服务器,则除非停止并再次运行它,否则该应用程序不会采用保留在数据库中的新连接,我想使其在运行时正常运行。并删除要自动处理的服务器。 这是我用于设置集成流程的conf类,我不确定是否有任何注释可以使此工作正常进行。有人可以指导吗? 让我知道是否需要更多信息
@Configuration
@Component
@EnableIntegration
public class FTIntegration {
public static final String TIMEZONE_UTC = "UTC";
public static final String TIMESTAMP_FORMAT_OF_FILES = "yyyyMMddHHmmssSSS";
public static final String TEMPORARY_FILE_SUFFIX = ".part";
public static final int POLLER_FIXED_PERIOD_DELAY = 5000;
public static final int MAX_MESSAGES_PER_POLL = 100;
private static final Logger LOG = LoggerFactory.getLogger(FTIntegration.class);
private static final String CHANNEL_INTERMEDIATE_STAGE = "intermediateChannel";
@Autowired
private IntegrationFlowContext flowContext;
/* pulling the server config from postgres DB*/
private final BranchRepository branchRepository;
@Value("${app.temp-dir}")
private String localTempPath;
public FTIntegration(BranchRepository branchRepository) {
this.branchRepository = branchRepository;
}
@Bean
public Branch myBranch(){
return new Branch();
}
/**
* The default poller with 5s, 100 messages, RotatingServerAdvice and transaction.
*
* @return default poller.
*/
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata poller(){
return Pollers
.fixedDelay(POLLER_FIXED_PERIOD_DELAY)
.maxMessagesPerPoll(MAX_MESSAGES_PER_POLL)
.transactional()
.get();
}
/**
* The direct channel for the flow.
*
* @return MessageChannel
*/
@Bean
public MessageChannel stockIntermediateChannel() {
return new DirectChannel();
}
/**
* Get the files from a remote directory. Add a timestamp to the filename
* and write them to a local temporary folder.
*
* @return IntegrationFlow
*/
public IntegrationFlow fileInboundFlowFromFTPServer(Branch myBranch){
final FtpInboundChannelAdapterSpec sourceSpecFtp = Ftp.inboundAdapter(createNewFtpSessionFactory(myBranch))
.preserveTimestamp(true)
.patternFilter("*.csv")
.deleteRemoteFiles(true)
.maxFetchSize(MAX_MESSAGES_PER_POLL)
.remoteDirectory(myBranch.getFolderPath())
.localDirectory(new File(localTempPath))
.temporaryFileSuffix(TEMPORARY_FILE_SUFFIX)
.localFilenameExpression(new FunctionExpression<String>(s -> {
final int fileTypeSepPos = s.lastIndexOf('.');
return DateTimeFormatter
.ofPattern(TIMESTAMP_FORMAT_OF_FILES)
.withZone(ZoneId.of(TIMEZONE_UTC))
.format(Instant.now())
+ "_"
+ s.substring(0,fileTypeSepPos)
+ s.substring(fileTypeSepPos);
}));
// Poller definition
final Consumer<SourcePollingChannelAdapterSpec> stockInboundPoller = endpointConfigurer -> endpointConfigurer
.id("stockInboundPoller")
.autoStartup(true)
.poller(poller());
IntegrationFlow flow = IntegrationFlows
.from(sourceSpecFtp, stockInboundPoller)
.transform(File.class, p ->{
// log step
LOG.info("flow=stockInboundFlowFromAFT, message=incoming file: " + p);
return p;
})
.channel(CHANNEL_INTERMEDIATE_STAGE)
.get();
// this.flowContext.registration(flow).id(myBranch.getId().toString()).register().toString();
//this.flowContext.registration(flow).id("fileInb").register();
return flow;
}
@Bean
public IntegrationFlow stockIntermediateStageChannel() {
IntegrationFlow flow = IntegrationFlows
.from(CHANNEL_INTERMEDIATE_STAGE)
.transform(p -> {
//log step
LOG.info("flow=stockIntermediateStageChannel, message=rename file: " + p);
return p;
})
//TODO
.channel(new NullChannel())
.get();
return flow;
}
public DefaultFtpSessionFactory createNewFtpSessionFactory(Branch branch){
final DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
factory.setHost(branch.getHost());
factory.setUsername(branch.getUsern());
factory.setPort(branch.getFtpPort());
factory.setPassword(branch.getPassword());
return factory;
}
}
这是删除服务器的控制器部分。
@Controller
public class BranchController {
private BranchService branchService;
private BranchToBranchForm branchToBranchForm;
//@Autowired
private Branch branch;
@Autowired
private FTIntegration ftIntegration;
private static final Logger LOG = LoggerFactory.getLogger(FTIntegration.class);
private static final String CHANNEL_INTERMEDIATE_STAGE = "intermediateChannel";
@Autowired
private IntegrationFlowContext flowContext;
@Autowired
public void setBranchService(BranchService branchService) {
this.branchService = branchService;
}
@Autowired
public void setBranchToBranchForm(BranchToBranchForm branchToBranchForm) {
this.branchToBranchForm = branchToBranchForm;
}
@RequestMapping( "/")
public String branch(){return "redirect:/branch/list";}
@RequestMapping({"/branch/list","/branch"})
public String listBranches(Model model){
model.addAttribute("branches",branchService.listAll());
return "branch/list";
}
@RequestMapping("/branch/showbranch/{id}")
public String getBranch (@PathVariable String id, Model model){
model.addAttribute("branch", branchService.getById(Long.valueOf(id)));
//addFlowFtp(id);
addFlowftp(id);
return "/branch/showbranch";
}
@RequestMapping("/branch/edit/{id}")
public String edit(@PathVariable String id, Model model){
Branch branch = branchService.getById(Long.valueOf(id));
BranchForm branchForm = branchToBranchForm.convert(branch);
model.addAttribute("branchForm",branchForm);
return "branch/branchform";
}
@RequestMapping("/branch/new")
public String newBranch(Model model){
model.addAttribute("branchForm", new BranchForm());
return "branch/branchform";
}
@RequestMapping(value = "/branch", method = RequestMethod.POST)
public String saveOrUpdateBranch(@Valid BranchForm branchForm, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "branch/branchform";
}
Branch savedBranch = branchService.saveOrUpdateBranchForm(branchForm);
return "redirect:/branch/showbranch/" + savedBranch.getId();
}
@RequestMapping("/branch/delete/{id}")
private String delete(@PathVariable String id){
branchService.delete(Long.valueOf(id));
flowContext.remove(id);
return "redirect:/branch/list";
}
private void addFlowftp(String name) {
branch = branchService.getById(Long.valueOf(name));
System.out.println(branch.getBranchCode());
IntegrationFlow flow = ftIntegration.fileInboundFlowFromFTPServer(branch);
this.flowContext.registration(flow).id(name).register();
}
答案 0 :(得分:0)
请参见Dynamic and runtime Integration Flows。
您可以使用此处介绍的技术在运行时添加/删除集成流。
编辑
这里是一个例子:
@SpringBootApplication
@RestController
public class So53042903Application {
public static void main(String[] args) {
SpringApplication.run(So53042903Application.class, args);
}
@Autowired
private IntegrationFlowContext flowContext;
@RequestMapping(path = "/add/{name}", method = RequestMethod.GET)
public String add(@PathVariable String name) {
addFlow(name);
System.out.println("added " + name);
return "added " + name;
}
@RequestMapping(path = "/remove/{name}", method = RequestMethod.GET)
public String remove(@PathVariable String name) {
this.flowContext.remove(name);
System.out.println("removed " + name);
return "removed " + name;
}
private void addFlow(String name) {
IntegrationFlow flow = IntegrationFlows.from(() -> "processing: " + name, e -> e
.poller(Pollers.fixedDelay(3_000)))
.log(Level.INFO, "foo", "payload")
.get();
this.flowContext.registration(flow).id(name).register();
}
}
和
added foo
2018-10-31 10:22:58.998 INFO 1768 --- [ask-scheduler-1] foo : processing: foo
2018-10-31 10:23:02.001 INFO 1768 --- [ask-scheduler-1] foo : processing: foo
2018-10-31 10:23:05.002 INFO 1768 --- [ask-scheduler-2] foo : processing: foo
2018-10-31 10:23:07.312 INFO 1768 --- [nio-8080-exec-2] o.s.i.endpoint.EventDrivenConsumer : Adding {bridge} as a subscriber to the 'bar.channel#1' channel
2018-10-31 10:23:07.312 INFO 1768 --- [nio-8080-exec-2] o.s.integration.channel.DirectChannel : Channel 'application.bar.channel#1' has 1 subscriber(s).
2018-10-31 10:23:07.312 INFO 1768 --- [nio-8080-exec-2] o.s.i.endpoint.EventDrivenConsumer : started bar.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
2018-10-31 10:23:07.312 INFO 1768 --- [nio-8080-exec-2] o.s.i.e.SourcePollingChannelAdapter : started bar.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
added bar
2018-10-31 10:23:07.312 INFO 1768 --- [ask-scheduler-3] foo : processing: bar
2018-10-31 10:23:08.008 INFO 1768 --- [ask-scheduler-1] foo : processing: foo
2018-10-31 10:23:10.316 INFO 1768 --- [ask-scheduler-2] foo : processing: bar
2018-10-31 10:23:11.009 INFO 1768 --- [ask-scheduler-4] foo : processing: foo
2018-10-31 10:23:13.318 INFO 1768 --- [ask-scheduler-5] foo : processing: bar
2018-10-31 10:23:14.011 INFO 1768 --- [ask-scheduler-3] foo : processing: foo
2018-10-31 10:23:16.322 INFO 1768 --- [ask-scheduler-6] foo : processing: bar
2018-10-31 10:23:16.614 INFO 1768 --- [nio-8080-exec-4] o.s.i.endpoint.EventDrivenConsumer : Adding {bridge} as a subscriber to the 'baz.channel#1' channel
2018-10-31 10:23:16.614 INFO 1768 --- [nio-8080-exec-4] o.s.integration.channel.DirectChannel : Channel 'application.baz.channel#1' has 1 subscriber(s).
2018-10-31 10:23:16.614 INFO 1768 --- [nio-8080-exec-4] o.s.i.endpoint.EventDrivenConsumer : started baz.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
2018-10-31 10:23:16.614 INFO 1768 --- [nio-8080-exec-4] o.s.i.e.SourcePollingChannelAdapter : started baz.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
added baz
2018-10-31 10:23:16.614 INFO 1768 --- [ask-scheduler-7] foo : processing: baz
2018-10-31 10:23:17.012 INFO 1768 --- [ask-scheduler-1] foo : processing: foo
2018-10-31 10:23:19.323 INFO 1768 --- [ask-scheduler-2] foo : processing: bar
2018-10-31 10:23:19.615 INFO 1768 --- [ask-scheduler-8] foo : processing: baz
2018-10-31 10:23:20.014 INFO 1768 --- [ask-scheduler-4] foo : processing: foo
2018-10-31 10:23:22.324 INFO 1768 --- [ask-scheduler-9] foo : processing: bar
2018-10-31 10:23:22.622 INFO 1768 --- [ask-scheduler-5] foo : processing: baz
2018-10-31 10:23:23.015 INFO 1768 --- [sk-scheduler-10] foo : processing: foo
2018-10-31 10:23:25.326 INFO 1768 --- [ask-scheduler-3] foo : processing: bar
2018-10-31 10:23:25.623 INFO 1768 --- [ask-scheduler-6] foo : processing: baz
2018-10-31 10:23:26.020 INFO 1768 --- [ask-scheduler-7] foo : processing: foo
2018-10-31 10:23:27.966 INFO 1768 --- [nio-8080-exec-6] o.s.i.e.SourcePollingChannelAdapter : stopped bar.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
2018-10-31 10:23:27.966 INFO 1768 --- [nio-8080-exec-6] o.s.i.endpoint.EventDrivenConsumer : Removing {bridge} as a subscriber to the 'bar.channel#1' channel
2018-10-31 10:23:27.966 INFO 1768 --- [nio-8080-exec-6] o.s.integration.channel.DirectChannel : Channel 'application.bar.channel#1' has 0 subscriber(s).
2018-10-31 10:23:27.966 INFO 1768 --- [nio-8080-exec-6] o.s.i.endpoint.EventDrivenConsumer : stopped bar.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
removed bar
2018-10-31 10:23:28.624 INFO 1768 --- [ask-scheduler-1] foo : processing: baz
2018-10-31 10:23:29.025 INFO 1768 --- [ask-scheduler-8] foo : processing: foo
2018-10-31 10:23:31.625 INFO 1768 --- [ask-scheduler-4] foo : processing: baz
2018-10-31 10:23:32.026 INFO 1768 --- [ask-scheduler-9] foo : processing: foo
2018-10-31 10:23:34.626 INFO 1768 --- [ask-scheduler-5] foo : processing: baz
2018-10-31 10:23:35.027 INFO 1768 --- [sk-scheduler-10] foo : processing: foo
2018-10-31 10:23:35.931 INFO 1768 --- [nio-8080-exec-7] o.s.i.e.SourcePollingChannelAdapter : stopped baz.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
2018-10-31 10:23:35.931 INFO 1768 --- [nio-8080-exec-7] o.s.i.endpoint.EventDrivenConsumer : Removing {bridge} as a subscriber to the 'baz.channel#1' channel
2018-10-31 10:23:35.931 INFO 1768 --- [nio-8080-exec-7] o.s.integration.channel.DirectChannel : Channel 'application.baz.channel#1' has 0 subscriber(s).
2018-10-31 10:23:35.932 INFO 1768 --- [nio-8080-exec-7] o.s.i.endpoint.EventDrivenConsumer : stopped baz.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
removed baz
2018-10-31 10:23:38.032 INFO 1768 --- [ask-scheduler-3] foo : processing: foo
2018-10-31 10:23:41.036 INFO 1768 --- [ask-scheduler-3] foo : processing: foo
2018-10-31 10:23:44.037 INFO 1768 --- [ask-scheduler-3] foo : processing: foo
2018-10-31 10:23:47.041 INFO 1768 --- [ask-scheduler-3] foo : processing: foo
2018-10-31 10:23:47.736 INFO 1768 --- [nio-8080-exec-9] o.s.i.e.SourcePollingChannelAdapter : stopped foo.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
2018-10-31 10:23:47.736 INFO 1768 --- [nio-8080-exec-9] o.s.i.endpoint.EventDrivenConsumer : Removing {bridge} as a subscriber to the 'foo.channel#1' channel
2018-10-31 10:23:47.736 INFO 1768 --- [nio-8080-exec-9] o.s.integration.channel.DirectChannel : Channel 'application.foo.channel#1' has 0 subscriber(s).
2018-10-31 10:23:47.736 INFO 1768 --- [nio-8080-exec-9] o.s.i.endpoint.EventDrivenConsumer : stopped foo.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
removed foo
2018-10-31 10:23:51.349 INFO 1768 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2018-10-31 10:23:51.350 INFO 1768 --- [on(2)-127.0.0.1] o.s.i.endpoint.EventDrivenConsumer : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2018-10-31 10:23:51.350 INFO 1768 --- [on(2)-127.0.0.1] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 0 subscriber(s).
2018-10-31 10:23:51.351 INFO 1768 --- [on(2)-127.0.0.1] o.s.i.endpoint.EventDrivenConsumer : stopped _org.springframework.integration.errorLogger
2018-10-31 10:23:51.351 INFO 1768 --- [on(2)-127.0.0.1] o.s.s.c.ThreadPoolTaskScheduler : Shutting down ExecutorService 'taskScheduler'
2018-10-31 10:23:51.352 INFO 1768 --- [on(2)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'