Web应用程序中的Spring SimpleThreadScope:容器池的一部分?

时间:2014-06-18 16:44:58

标签: java spring web-applications

有一个公开加密功能的服务。我们不需要清理,也不希望每次/每次会话都创建对象。但是每个线程我需要一个单独的对象。

在Web应用程序中 - 范围是否为Web容器的线程池?

春季3和4实施是否相同?

我们计划使用它的另一个地方是缓存SimpleDateFormat对象。再次不需要清理方法。

4 个答案:

答案 0 :(得分:4)

从3.0版开始,Spring有一个基本的线程范围概念:SimpleThreadScope。看起来它可以满足您的要求,但它有一些局限性:

  • 默认情况下,它没有使用容器注册,但必须明确地
  • 它不会对其bean执行清理。

如果您可以满足这些限制,则可以以编程方式注册范围:

Scope threadScope = new SimpleThreadScope();
appContext.getBeanFactory().registerScope("thread", threadScope);

或在xml config中:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="thread">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>

这在Spring 3和Spring 4中的工作方式相同。如果要在单例bean中注入线程范围的bean,则必须在其上声明一个aop scoped-proxy:

<bean id="bar" class="x.y.Bar" scope="thread">
    <property name="name" value="Rick"/>
    <aop:scoped-proxy/>
</bean>
<bean id="foo" class="x.y.Foo">
    <property name="bar" ref="bar"/>
</bean>

(Spring Framework Reference Documentation中的所有示例)。

如果您需要进行一些清理,可以查看显示SimpleThreadScope增强版本的此文档Spring by Example Custom Thread Scope Module

但是我不确定你真的想要那个,除非所有线程不断使用线程范围的bean,否则内存不是真正的问题。因为在该设计模式中,如果一次只有一个会话需要bean,但它由多个线程服务(假设其他请求不需要bean),所有线程将获得bean的不同实例,而使用池只会使用一个实例。

您将在SO How to pool objects in Spring?的另一篇文章中找到使用CommonsPoolTargetSource和Apache公共池的示例。摘自帖子:

<bean id="simpleBeanTarget" class="com.bean.SimpleBean" scope="prototype"/>

<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
    <property name="targetBeanName" value="simpleBeanTarget" />
    <property name="maxSize" value="2" />
</bean>

<bean id="simpleBean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="poolTargetSource" />
</bean>

该示例使用ProxyFactoryBean提供aop代理,以允许在单个bean中注入simpleBean,前提是它作为接口注入。

答案 1 :(得分:1)

ThreadLocal有线程范围的对象。 其次,SimpleDateFormat和DateFormats通常不同步。所以要注意那里的线程问题。 顺便说一句,当你说“每个线程”时,你的意思是每个请求?正如the java doc for SimpleThreadScope所述,通常最好在Web环境中使用RequestScope。

Spring可以使用specific scopes创建bean,例如原型,请求,您可能需要考虑。正如@Sairam所提到的,生命周期管理也值得一提。

答案 2 :(得分:0)

在spring框架中,为了获得每个线程的单独对象,我们可以通过将bean作为原型来实现这一点。

来自reference。,

<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>

Spring 3&amp;图4分别针对该特定情况。关于对象的清理,原型范围的行为与来自同一参考文档的不同。

  

与其他作用域相比,Spring不管理原型bean的完整生命周期:容器实例化,配置和组装原型对象,并将其交给客户端,没有该原型实例的进一步记录。因此,尽管无论范围如何都在所有对象上调用初始化生命周期回调方法,但在原型的情况下,不会调用已配置的销毁生命周期回调。客户端代码必须清理原型范围的对象并释放原型bean所持有的昂贵资源。

答案 3 :(得分:-1)

为您提供解决方案:

  1. 提供您自己的FactoryBean来创建服务bean。
  2. 在你的FactoryBean中,你shuld使用ThreadLocal来保存你的bean,如果不存在,创建一个并将其保存到ThreadLocal,下次从ThreadLocal中检索它!