java - 并行执行 Spring 初始化 Bean

标签 java spring initialization

我有多个 Spring InitializingBean 类,我希望它们都并行运行 afterPropertiesSet()。然而,当我运行一个小示例时,它们是同步执行的。有什么办法可以并行执行它们吗?

下面是一个初始化 bean 的示例,可用于测试我所指的内容。当创建多个这样的类(即 InitBeanOneInitBeanTwo...)时,日志显示它们正在同步运行。

我想到的一个想法是让一个初始化 bean 异步初始化所需的类。不过,这是最后的选择,因为我想单独利用每个类的初始化 bean,而不需要其他依赖类。

@Component
public class InitBean implements InitializingBean {

    private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);

    @Override
    public void afterPropertiesSet() throws Exception {
        LOGGER.info("BEGIN: InitBean");
        TimeUnit.SECONDS.sleep(5);
        LOGGER.info("END: InitBean");
    }
}

最佳答案

您应该将代码重新定位到事件监听方法,并使用@Async标记该方法。

确保异步功能设置正确。请参阅:How To Do @Async in Spring .

您应该让该方法在 Spring 框架触发 ApplicationReadyEvent 时被触发。 .

@Component
public class InitBean {
    private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);

    @Async
    @EventListener
    public void onApplicationReady(ApplicationReadyEvent event) throws Exception {
        LOGGER.info("BEGIN: onApplicationReady");
        TimeUnit.SECONDS.sleep(5);
        LOGGER.info("END: onApplicationReady");
    }
}

警告:通过这样做,可能会在调用此方法之前/期间调用其他方法。如果该方法执行其他方法所需的任何类型的初始化,您需要处理它,例如使用CountDownLatch .


更新

如果您需要应用程序延迟启动序列的完成,直到所有异步方法完成,我认为您需要自己处理。

使用与InitializingBean相同的方法创建接口(interface)AsyncInitializingBean ,然后创建一个名为 AsyncBeanInitializer@Component Autowiring AsyncInitializingBean[] (或 List),然后它使用 ContextRefreshedEvent 上的 ExecutorService 执行所有方法。

@Component
public class InitBean implements AsyncInitializingBean { // <== Change interface (only change needed)

    private final static Logger LOGGER = LoggerFactory.getLogger(InitBean.class);

    @Override
    public void afterPropertiesSet() throws Exception {
        LOGGER.info("BEGIN: InitBean");
        TimeUnit.SECONDS.sleep(5);
        LOGGER.info("END: InitBean");
    }
}
public interface AsyncInitializingBean {
    void afterPropertiesSet() throws Exception;
}
@Component
public class AsyncBeanInitializer {
    private final static Logger LOGGER = LoggerFactory.getLogger(AsyncBeanInitializer.class);

    @Autowired(required = false)
    private AsyncInitializingBean[] beans;

    @EventListener
    public void onContextRefreshed(@SuppressWarnings("unused") ContextRefreshedEvent event) throws Exception {
        if (this.beans == null || this.beans.length == 0)
            return;
        ExecutorService executorService = Executors.newWorkStealingPool();
        try {
            AtomicInteger failed = new AtomicInteger();
            for (AsyncInitializingBean bean : beans) {
                executorService.submit(() -> {
                    try {
                        bean.afterPropertiesSet();
                    } catch (Exception e) {
                        failed.incrementAndGet();
                        LOGGER.error("Async afterPropertiesSet() method failed: " + e, e);
                    }
                });
            }
            executorService.shutdown();
            executorService.awaitTermination(60, TimeUnit.MINUTES);
            if (failed.get() != 0)
                throw new RuntimeException(failed.get() + " Async afterPropertiesSet() methods failed. See log for details.");
        } finally {
            executorService.shutdownNow();
        }
    }
}

关于java - 并行执行 Spring 初始化 Bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60497894/

相关文章:

java - 如何(以及何时)初始化需要访问仅在运行时已知的其他 bean 的 Spring bean?

javascript - 如何初始化命名空间内的所有方法?namespaces javascript INITIALIZING ALL methods

java - Elastic Search - Java BoolQuery API 应过滤所有不匹配的内容

java - 如何在 Mapreduce 程序中遍历 Text 值的迭代器两次?

java - 将普通的Java代码转换为hadoop代码而不使用mapreduce?

java - Spring 安全 : ClassNotFoundException or IllegalArgumentException on deploy

java - android:获取当前收到的消息

java - 创建名称为 'dataSource' : Invocation of init method failed 的 bean 时出错

java - 有什么方法可以使用自定义 BeanWrapper 实现来加载应用程序上下文

C++ 静态存储持续时间对象在 main() 之前初始化