如何使用Pooled Spring bean而不是Singleton?

时间:2011-06-27 13:29:50

标签: java multithreading spring ejb

出于效率原因,我有兴趣限制同时使用Spring应用程序上下文的bean的线程数(我不希望无限线程数在我的中进行处理有限的记忆)。

通过执行以下操作,我发现here(spring文档)是一种通过将bean集中在EJB样式中来实现此目的的方法:

  • 将目标bean声明为范围“prototype”。
  • 声明将提供有限数量的池化“目标”实例的池提供程序。
  • 声明一个“ProxyFactoryBean”,这个功能对我来说并不清楚。

以下是此bean的声明:

<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject" 
    scope="prototype">
  ... properties omitted
</bean>

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

<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="targetSource" ref="poolTargetSource"/>
  <property name="interceptorNames" value="myInterceptor"/>
</bean>

我的问题是,当我声明另一个bean使用“businessObjectTarget”的池化实例时,我应该怎么做?我的意思是,当我尝试做这样的事情时:

<bean id="clientBean" class="com.mycompany.ClientOfTheBusinessObject">
  <property name="businessObject" ref="WHAT TO PUT HERE???"/>
</bean>

“ref”的价值应该是什么?

5 个答案:

答案 0 :(得分:4)

您无法使用属性来获取原型实例 一种选择是使用查找方法(参见chapter 3.3.7.1
将bean添加到代码中的另一个选择:让com.mycompany.ClientOfTheBusinessObject实现ApplicationContextAware接口,然后调用context.getBean("clientBean")

答案 1 :(得分:0)

我很确定你可以用一种不太复杂的方式限制同步线程的数量。您是否看过Java Concurrency API,特别是Executors.newFixedThreadPool()?

答案 2 :(得分:0)

我使用java-configuration在接口上构建代理,使用apache commons-pool处理池,以实现调用级别池。

答案 3 :(得分:0)

请注意spring示例中第三个bean的名称: - “businessObject”

这意味着你应该访问公共池的bean。

对于您的情况,如果您需要自己的客户端bean,您可以按如下方式使用它。 但在这种情况下,不需要businessObject。: -

<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject" 
    scope="prototype">

  ... properties omitted
</bean>

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

<bean id="clientBean" class="com.mycompany.ClientOfTheBusinessObject">
 <property name="poolTargetSource" ref="poolTargetSource"/>
</bean>


Java classes:-
public class ClientOfTheBusinessObject{
     CommonsPoolTargetSource poolTargetSource;
//<getter and setter for poolTargeTSource>
  public void methodToAccessCommonPool(){
     //The following line gets the object from the pool.If there is nothing left in the pool then the thread will be blocked.(The blocking can be replaced with an exception by changing the properties of the CommonsPoolTargetSource bean)
     MyBusinessObject mbo = (MyBusinessObject)poolTargetSource.getTarget();
     //Do whatever you want to do with mbo
     //the following line puts the object back to the pool
     poolTargetSource.releaseTarget(mbo);
  }
}

答案 4 :(得分:0)

我使用基于注释的配置来做到这一点:

  1. 我确实将我的BusinessObject类创建为POJO并以此方式进行了注释:

    @Component("businessObject")
    @Scope("prototype")
    public class BusinessObject { ... }
    

    我给它指定了一个特定的名称,并确实将其标记为 prototype ,这样Spring不会为其创建单例实例。每次需要bean时,Spring都会创建一个新实例。

  2. 在我的@Configuration类中(如果使用Spring Boot,则在@SpringBootApplication类中,我创建了一个CommonsPool2TargetSource实例来容纳BusinessObject个实例:

    @Bean
    public CommonsPool2TargetSource pooledTargetSource() {
        final CommonsPool2TargetSource commonsPoolTargetSource = new CommonsPool2TargetSource();
        commonsPoolTargetSource.setTargetBeanName("businessObject");
        commonsPoolTargetSource.setTargetClass(BusinessObject.class);
        commonsPoolTargetSource.setMaxSize(maxPoolSize);
        return commonsPoolTargetSource;
    }
    

    在这里,我表示该池将容纳BusinessObject个实例。请注意,我的maxPoolSize=?值设置为我要保存在池中的BusinessObject个实例的最大数量。

  3. 最后,我确实以这种方式访问​​池实例:

    @Autowired
    private CommonsPool2TargetSource pooledTargetSource;
    
    void someMethod() {
        // First I retrieve one pooled BusinessObject instance
        BusinessObject businessObject = (BusinessObject)pooledTargetSource.getTarget();
    
        try {
            // Second, I do some logic using the BusinessObject instance gotten
        } catch (SomePossibleException e) {
            // Catch and handle any potential error, if any
        } finally {
    
            // Finally, after executing my business logic
            // I release the BusinessObject instance so that it can be reused
            pooledTargetSource.releaseTarget(businessObject);
        }
    }
    

    始终确保从池中释放BusinessObject 借来的非常重要,这与业务逻辑是否成功完成或出错无关。否则,在借用所有实例且从未释放它们的情况下,该池可能会变空,并且对实例的任何进一步请求将永远被阻止。