简体   繁体   English

Spring Boot 中的原型 bean 未触发调度方法

[英]Prototyped bean not triggering Scheduled method in Spring Boot

I'm using Java 17, spring-boot 2.7.3 and spring 5.3.22 dependencies.我正在使用 Java 17、spring-boot 2.7.3 和 spring 5.3.22 依赖项。

I have prototyped beans as follows:我有如下原型bean:

@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:我的应用程序 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.我将InsertTransactionDetailsByScheduleAPIInteractor也注释为原型,以便在每次计划执行时都有一个内部 bean 的新实例,但不知何故,@Scheduled 方法仅在我有一个 singleton InsertTransactionDetailsByScheduleAPIInteractor bean 时运行,在我的用例中我不能拥有,否则我不会关闭 FTP 连接。 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.我知道在 Spring 4.3 之前,@Scheduled 方法仅适用于 Singleton bean,但如前所述,我使用的是 Spring 版本 5.3.22。

You are using Spring but that doesn't mean everything has to be managed by Spring.您正在使用 Spring 但这并不意味着一切都必须由 Spring 管理。 There is nothing wrong with opening an SFTP Session inside your class when you need it and close it afterwards.在需要时在 class 中打开 SFTP Session 并在之后关闭它没有任何问题。 You can probably even use a try-with-resources as I expect the Session to be a AutoClosable which can be used.您甚至可以使用 try-with-resources,因为我希望Session是可以使用的AutoClosable

So in short manually create the objects you need inside your scheduled job and cleanup after the job finished.因此,简而言之,在计划的作业中手动创建您需要的对象,并在作业完成后进行清理。 This way your scheduler can be a regular singleton and properly cleanup after itself.这样,您的调度程序可以是常规的 singleton 并在其自身之后进行适当的清理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM