初始化所有上下文的Spring事件

时间:2017-09-18 20:33:03

标签: java spring

类似的问题已得到解答......

此处:Listener for server starup and all spring bean loaded completely

此处:How to add a hook to the application context initialization event?

和其他几个地方。

在我的主应用程序中,当Root Spring上下文初始化时,它将触发三个子上下文进行初始化。在侦听要触发的事件时(基于ContextRefreshedEvent),这会导致四个事件总数。这并不会向消费者提供有关应用程序Spring环境总体状态的准确信息。

很遗憾,我无法更改主要应用程序。我现在正在努力解决的代码打包为jar,并使用插件架构加载到主应用程序中。我可以毫无问题地挂钩应用程序的Spring上下文,并且我可以成功接收ContextRefreshEvent触发器。

我正在寻找的是一种了解主应用程序中的所有Spring应用程序上下文是否都已完成的方法。我尝试的一件事是手动跟踪应用程序上下文的开始和完成(使用地图),以便我可以告诉所有已知的应用程序上下文何时完成初始化。这对我来说没有用,因为我发现在Spring的刷新操作中ContextStartedEvent没有触发。

可能对我有用的其他事情将是知道有多少应用程序上下文或需要加载多少个bean。这样我就可以在完成后跟踪它们并最终知道所有应用程序上下文都已完成。

任何想法都会受到赞赏。

修改

为了尽可能地问一个问题,我在实施方面使这个问题过于规范。这是我试图解决的实际问题(以问题的形式):

如果在Web应用程序的上下文中成功部署了webapp的内容,那么在webapp中打包为jar的插件怎么可能呢?

通过测试,我认为断言Spring上下文的初始化与通过Tomcat的应用程序的部署阶段同义是相当安全的。这可能是错误的,但排队得很好。

从使用Spring专门扩展修复的范围,我能够找到问题的解决方案。我将把它作为一个单独的答案发布。

2 个答案:

答案 0 :(得分:0)

自Spring 2.5.X< 4.X

你可以做的一件事是听ContextStartedEvent - s,将它们添加到地图中,然后一旦ContextRefreshedEvent - s被触发,等待所有上下文刷新。

如果上下文多次刷新,但仍然可能不安全......但至少要有一个起点。

截至4月4日

阅读ContextRefreshedEvent javadocs:

Event raised when an {@code ApplicationContext} gets initialized or refreshed.

这意味着您可以拥有自己的逻辑来跟踪上下文是已初始化还是已刷新

@EventListener( { ContextRefreshedEvent.class } )
void contextRefreshedEvent( ContextRefreshedEvent e ) {
    ApplicationContext context = ( ApplicationContext ) e.getSource();
    System.out.println( "a context refreshed event happened for context: " + context.getDisplayName() );
}

含义 - 您第一次获得具有该上下文的事件时 - 您将知道它已已初始化。以下时间 - 您将知道它是刷新

残酷简单(无优化)您可以执行以下操作:

private final Map<String, String> contextStatuses = new HashMap<>();

@EventListener( { ContextRefreshedEvent.class } )
public void contextRefreshedEvent( ContextRefreshedEvent e ) {
    ApplicationContext context = ( ApplicationContext ) e.getSource();

    if ( !contextStatuses.containsKey( context.getDisplayName() ) ) { // initialized
        contextStatuses.put( context.getDisplayName(), "initialized" );
    } else { // refreshed
        contextStatuses.put( context.getDisplayName(), "refreshed" );
    }

    checkAllContextsRefreshed();
}

private void checkAllContextsRefreshed() {
    for ( String status : contextStatuses.values() ) {
        if ( !"refreshed".equals( status ) ) {
            return;
        }
    }

    doWhenAllContextsRefreshed();
}

答案 1 :(得分:0)

根据我的问题编辑,这是我采用的解决方案:

在主应用程序中打包的插件中,我使用JMX对Catalina下的WebModule类型的stateName属性添加了一个检查。这不是我使用的确切代码,但为简单起见,逻辑看起来像这样:

$nightStart = '22:00';
$nightEnd = '07:00';

$workers = array(
    '0' => array(
        'name'  => 'Lyons',
        'start' => '15:15',
        'end'   => '23:45'
    ),

    '1' => array(
        'name'  => 'Santos',
        'start' => '10:00',
        'end'   => '22:00'
    ),

    '2' => array(
        'name'  => 'Montgomery',
        'start' => '22:30',
        'end'   => '08:00'
    )
); 


foreach ($workers as $worker) {
    $length_of_work = abs(strtotime($worker['start']) - strtotime($worker['end'])) / 3600;
    $work_in_daytime = '';
    $work_in_nighttime = '';
}

正如我在编辑中提到的,将Tomcat部署等同于Spring上下文初始化是接近的,但最终它并不是一个公平的比较。使用此JMX端点可以非常准确地表示Tomcat部署的状态。