使用Spring在Tomcat启动期间委派处理

时间:2015-09-26 11:57:33

标签: java multithreading spring tomcat

我已经定义了一个bean,它需要在@PostConstruct生命周期阶段(启动期间)进行一些繁重的处理。

就目前而言,我在处理循环的每次迭代中向执行者服务提交一个新的Callable。我在成员变量中保留了从这些提交中返回的Future对象的列表。

@Component
@Scope("singleton")
public class StartupManager implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private ExecutorService executorService;

    private final Map<Class<?>, Optional<Action>> actionMappings = new ConcurrentHashMap<>();
    private final List<Future> processingTasks = Collections.synchronizedList(new ArrayList<>());

    @PostConstruct
    public void init() throws ExecutionException, InterruptedException {

        this.controllers.getHandlerMethods().entrySet().stream().forEach(handlerItem -> {

            processingTasks.add(executorService.submit(() -> {

                // processing

            }));

        });

    }

}

这个bean实现了ApplicationListener接口,因此它可以侦听ContextRefreshedEvent,它允许我检测应用程序何时完成启动。我使用这个处理程序循环遍历Futures列表并调用阻塞get方法,该方法确保在应用程序继续之前已经发生了所有处理。

@Override
public void onApplicationEvent(ContextRefreshedEvent  applicationEvent) {
    for(Future task : this.processingTasks) {
        try {
            task.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new IllegalStateException(e.getMessage());
        }
    }
}

我的第一个问题...是否将actionMapping流更改为parallelStream,以实现与向执行程序服务提交任务相同的功能?有没有办法可以将现有的执行程序服务传递到并行流中,以便使用我为bean定义的线程池大小?

其次..作为处理的一部分..将读取actionMappings地图并将条目放入其中。这足以使这个Map成为ConcurrentHashMap以使其在这种情况下的线程安全吗?

其次是实现ApplicationListener接口并监听ContextRefreshedEvent是检测应用程序何时启动的最佳方法,因此通过阻止来强制完成未处理的任务?或者这可以用另一种方式完成吗?

感谢。

1 个答案:

答案 0 :(得分:1)

  1. 关于使用parallelStream():不,这正是使用此方法的主要缺点。它应该仅在线程池大小无关紧要时使用,因此我认为基于ExecutorService的方法很好。

    由于您正在使用Java 8,因此您也可以使用CompletableFuture.supplyAsync()方法,该方法的重载需要Executor。由于ExecutorService延长Executor,您可以将ExecutorService传递给您,并且您已完成!

  2. 我认为ConcurrentHashMap没问题。它确保了所有操作中的线程安全性,特别是在需要添加或修改条目时。

  3. ContextRefreshedEvent何时被解雇?根据Javadoc:

      

    ApplicationContext初始化或刷新时引发的事件。

    并不保证您的onApplicationEvent()方法只被调用一次,也就是说,当您的bean被正确初始化时,包括执行@PostConstruct - 注释方法。

    我建议您实施BeanPostProcessor界面并将Future - 检查逻辑放在postProcessAfterInitialization()方法中。两个BeanPostProcessor方法分别在InitializingBean.afterPropertiesSet()方法(如果存在)之前和之后调用。

  4. 我希望这会有所帮助......

    干杯,

    杰夫

相关问题