对于Spring bean定义,覆盖default-lazy-init = true

时间:2012-02-29 13:40:36

标签: java spring

我正在维护一个庞大的Java EE系统。大多数业务逻辑从EJB转换为POJO:在多个spring上下文配置文件中配置。 EJB:s主要用作Facade,它从由前面提到的所有spring上下文配置文件组成的上下文中查找业务逻辑spring bean。为此,我们使用Spring框架提供的AbstractStatelessSessionBean。

所有这些配置文件都具有default-lazy-init = true指令,这意味着在系统实际使用业务逻辑bean之前不会创建它们。这在大多数情况下是可取的,因为在开发者模式下重新发布会变得更快。

但是当进行大型合并时,我们在查找所有配置错误时遇到问题,例如缺少依赖项。

我的想法是编写某种形式的集成测试,目的是找到这些错误。我认为,这意味着我需要找到一种方法来在创建应用程序上下文时覆盖所有default-lazy-init = true声明。

有没有办法以编程方式执行此操作,或者可能使用包含所有实际上下文文件的某些仅测试上下文文件?

4 个答案:

答案 0 :(得分:15)

假设您目前有一个包含所有bean定义的applicationContext.xml文件:

<beans default-lazy-init="true">

    <!-- all your beans -->

</beans>

将其重命名为applicationContext-main.xml或其他内容并删除default-lazy-init="true"属性。现在创建两个applicationContext.xml文件:

<beans default-lazy-init="true">

    <import resource="applicationContext-core.xml"/>

</beans>

<beans default-lazy-init="false">

    <import resource="applicationContext-core.xml"/>

</beans>

正如您所看到的,唯一的区别是default-lazy-init的价值。在开发期间,您的团队可以使用包含applicationContext.xml所有bean的lazy-init的旧版本。在登台和测试环境中,将其切换到后者,以便急切地创建applicationContext-core.xml中包含的所有bean。

答案 1 :(得分:8)

我认为最好的方法是控制bean的延迟初始化是将所有配置文件中的default-lazy-init保留在除Tomasz Nurkiewicz建议的最顶层之外。但是,在这种情况下,我需要快速而又脏的修复来验证所有bean定义。 (这是一个改变延迟初始化策略的过程。)

我想出了一个简单的BeanFactoryPostProcessor,似乎可以完成这项任务:

public class NonLazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            beanFactory.getBeanDefinition(beanName).setLazyInit(false);
        }
    }
}

如果包含在上下文文件中,它将覆盖由任何包含的上下文文件设置的延迟初始化标志。

<beans default-lazy-init="false">
    <bean class="example.NonLazyInitBeanFactoryPostProcessor" />
    <import resource="applicationContext-core.xml"/>
</beans>

如果我尝试从上面的xml创建一个上下文,那么之前由延迟初始化隐藏的配置错误将立即显示为异常。

答案 2 :(得分:1)

此PostProcessor中有一个'但是'

for (String beanName : beanFactory.getBeanDefinitionNames()) {
        beanFactory.getBeanDefinition(beanName).setLazyInit(false);
    }

这个for循环只会遍历最顶层的bean,不包括例如内部(本地)bean定义......

答案 3 :(得分:0)

您无法从上下文访问扫描程序 - 它完全是私密的,但由于您可以进入源代码,因此您可以查看设置自己的内容所需的内容。我使用Spring自己的ReflectionTestUtils在上下文中设置我自己配置​​的扫描程序:

    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
    BeanDefinitionDefaults defaults = new BeanDefinitionDefaults();
    defaults.setLazyInit(true);
    scanner.setBeanDefinitionDefaults(defaults);
    ReflectionTestUtils.setField(context, "scanner", scanner);
    context.scan("com.some.path");

您可以在组件扫描发生之前访问应用程序上下文的任何地方执行此操作。