I'm using Java 17, spring-boot 2.7.3 and spring 5.3.22 dependencies.
I have prototyped beans as follows:
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class InsertTransactionDetailsByScheduleAPIInteractor
implements InsertTransactionDetailsByScheduleAPIInputBoundary {
private final InsertTransactionsInputBoundary insertTransactionsInputBoundary;
private final RetrieveFileFromSecureFileTransferProtocolInputBoundary retrieveFileFromSecureFileTransferProtocolInputBoundary;
public InsertTransactionDetailsByScheduleAPIInteractor(
final InsertTransactionsInputBoundary insertTransactionsInputBoundaryParam,
@Qualifier(Constants.PROTOTYPE_RETRIEVE_FILE_BEAN_QUALIFIER) final RetrieveFileFromSecureFileTransferProtocolInputBoundary retrieveFileFromSecureFileTransferProtocolInputBoundaryParam) {
super();
this.insertTransactionsInputBoundary = insertTransactionsInputBoundaryParam;
this.retrieveFileFromSecureFileTransferProtocolInputBoundary = retrieveFileFromSecureFileTransferProtocolInputBoundaryParam;
}
/**
* {@inheritDoc}
*/
@Override
// @Scheduled(cron = "* 30 1 * * *", zone = "America/Sao_Paulo")
@Scheduled(initialDelay = 5, fixedRate = 1, timeUnit = TimeUnit.SECONDS)
public void insertTransactionsBySchedule() throws Exception {
this.insertTransactionsInputBoundary.insertTransactions(LocalDate.now(Constants.DEFAULT_ZONE_ID),
this.retrieveFileFromSecureFileTransferProtocolInputBoundary);
}
}
@Configuration
@RefreshScope
class FTPConfiguration {
private final ConsulProperties consulProperties;
public FTPConfiguration(final ConsulProperties consulPropertiesParam) {
super();
this.consulProperties = consulPropertiesParam;
}
@Bean
@RequestScope
@Primary
RetrieveFileFromSecureFileTransferProtocolInputBoundary createRequestScopedRetrieveFileFromSecureFileTransferProtocolBean()
throws Exception {
return this.createRetrieveFileFromSecureFileTransferProtocolBean(true);
}
@Bean
@RequestScope
@Primary
ChannelSftp createRequestScopedSecureFileTransferProtocolChannel() throws JSchException {
return this.createSFTPChannel(true);
}
@Bean(destroyMethod = Constants.FTP_SESSION_BEAN_DESTROY_METHOD)
@RequestScope
@Primary
Session createRequestScopeSecureFileTransferProtocolSession() throws JSchException {
return this.createSFTPSession();
}
@Bean(Constants.PROTOTYPE_RETRIEVE_FILE_BEAN_QUALIFIER)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
RetrieveFileFromSecureFileTransferProtocolInputBoundary createPrototypeScopedRetrieveFileFromSecureFileTransferProtocolBean()
throws Exception {
return this.createRetrieveFileFromSecureFileTransferProtocolBean(false);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
ChannelSftp createPrototypeScopedSecureFileTransferProtocolChannel() throws JSchException {
return this.createSFTPChannel(false);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Session createPrototypeScopedSecureFileTransferProtocolSession() throws JSchException {
return this.createSFTPSession();
}
private RetrieveFileFromSecureFileTransferProtocolInputBoundary createRetrieveFileFromSecureFileTransferProtocolBean(
final boolean isRequestScope) throws Exception {
final var channelSFTP = isRequestScope ? this.createRequestScopedSecureFileTransferProtocolChannel()
: this.createPrototypeScopedSecureFileTransferProtocolChannel();
return new RetrieveFileFromSecureFileTransferProtocolInteractor(channelSFTP,
new ListDirFilesFromSecureFileTransferProtocolInteractor(channelSFTP));
}
private ChannelSftp createSFTPChannel(final boolean isRequestScope) throws JSchException {
final var channel = (isRequestScope ? this.createRequestScopeSecureFileTransferProtocolSession()
: this.createPrototypeScopedSecureFileTransferProtocolSession()).openChannel("sftp");
channel.connect(this.consulProperties.getChannelTimeout());
return (ChannelSftp) channel;
}
private Session createSFTPSession() throws JSchException {
final var session = new JSch().getSession(this.consulProperties.getUsername(), this.consulProperties.getHost(),
this.consulProperties.getPort());
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(this.consulProperties.getFtpPassword());
session.connect(this.consulProperties.getSessionTimeout());
return session;
}
}
My application class:
@SpringBootApplication
@EnableCaching
@EnableScheduling
public class Application implements Closeable {
private static ConfigurableApplicationContext run;
public static void main(final String[] args) {
Application.run = SpringApplication.run(Application.class, args);
}
@Override
public void close() {
Application.run.close();
}
}
I annotated the InsertTransactionDetailsByScheduleAPIInteractor also as prototype in order to have a new instance of the inner beans per schedule execution, but somehow the @Scheduled method only runs when I have a singleton InsertTransactionDetailsByScheduleAPIInteractor bean, which in my use case I can't have, otherwise I wouldn't close FTP connection. I know before Spring 4.3, @Scheduled methods only works with Singleton beans, but as mentioned before I'm using Spring version 5.3.22.