我怎样才能确保Spring构造一次bean

时间:2015-08-07 17:18:36

标签: java spring ehcache

我有一个复杂的企业环境,有多个项目相互依赖。配置由spring处理,包括疯狂的数字导入和不包括。

默认情况下,Spring可以多次构造一个具有相同名称的bean。特别是在多个Spring上下文的情况下。每个上下文都有自己的同一个单例bean的实例。 Singleton在Spring架构师中并不是真正的单身人士。头脑...

不幸的是,在我的情况下,一个bean永远不会被创建多次。

有没有办法强制Spring检查bean是否已经创建了它而不是尝试再次调用它的构造函数?

特别是,bean在内部创建了ehcache的CacheManager并失败,因为无法创建两次具有相同名称的CacheManager。

    <bean id="cacheService" class="somepackage.CacheServiceImpl">
        <constructor-arg index="0" value="/somepackage/ehcache.xml" />
    </bean>

我无法控制CacheServiceImpl代码。我只能改变它周围的配置。

2 个答案:

答案 0 :(得分:2)

不同的Spring应用程序上下文彼此不了解。就每个上下文而言,您的对象单身。但是,听起来你不希望有多个上下文。

你是如何创造背景的?您的应用程序应创建ApplicationContext的单个实例(可能在main或附近的某个位置)。任何需要应用程序上下文的内容都应该注入或者ApplicationContextAware

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-instantiation

您提到了“复杂的企业环境”。在我工作的地方最有效的方法是让一个项目管理Spring。假设您的所有项目都在同一个应用程序中运行(否则Spring无法真正帮助您),可能有一些项目会启动所有项目。对我们来说,这是一个内置于战争并部署到我们服务器的项目。

答案 1 :(得分:1)

我终于明白了。加载上下文两次的原因是在第一次上下文加载期间发生的隐藏错误。下面是一个冗长乏味的解释。

在第一次调用spring方法DefaultTestContext.getApplicationContext()时,应该加载Context。

有一个类DefaultCacheAwareContextLoaderDelegate,它负责实际加载上下文一次并将其缓存以备将来使用。方法代码如下:

@Override
public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) {
    synchronized (this.contextCache) {
        ApplicationContext context = this.contextCache.get(mergedContextConfiguration);
        if (context == null) {
            try {
                context = loadContextInternal(mergedContextConfiguration);
                if (logger.isDebugEnabled()) {
                    logger.debug(String.format("Storing ApplicationContext in cache under key [%s]",
                            mergedContextConfiguration));
                }
                this.contextCache.put(mergedContextConfiguration, context);
            }
            catch (Exception ex) {
                throw new IllegalStateException("Failed to load ApplicationContext", ex);
            }
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug(String.format("Retrieved ApplicationContext from cache with key [%s]",
                        mergedContextConfiguration));
            }
        }

        this.contextCache.logStatistics();

        return context;
    }
}

显然,当在loadContextInternal()调用期间抛出除Exception之外的Throwable时,应用程序上下文不会被放入缓存中。

显然,即使运行单个JUnit测试,也会多次调用getApplicationContext()方法,期望第二次自已缓存后不再需要加载它。

如果在第一次加载期间抛出错误,它将被隐藏,JUnit / Spring继续测试,直到它第二次调用getApplicationContext()。这就是它捕获异常和崩溃的地方,因为ehcache不希望CacheManager多次初始化。