How to use Pooled Spring beans instead of Singleton ones?

前端 未结 5 1225
后悔当初
后悔当初 2021-01-14 16:45

For efficiency reasons, I am interested in limiting the number of threads that simultaneously uses the beans of the Spring application context (I don\'t want an unli

相关标签:
5条回答
  • 2021-01-14 17:19

    i used java-configuration to construct a proxy over the interface that handles pooling using apache commons-pool to achieve invocation-level-pooling.

    0 讨论(0)
  • 2021-01-14 17:21

    I'm pretty sure you can limit the number of simultaneous threads in a less convoluted way. Did you look at the Java Concurrency API, specifically at the Executors.newFixedThreadPool() ?

    0 讨论(0)
  • 2021-01-14 17:25

    Please note the name of the third bean in the spring example:-"businessObject"

    It means this the bean from where you are supposed to access the common pool.

    For your case if you need your own client bean you may have it as follows. But in such a case businessObject is not required.:-

    <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);
      }
    }
    
    0 讨论(0)
  • 2021-01-14 17:26

    You cannot use properties to get instances of prototypes.
    One option is to use the lookup methods (see chapter 3.3.7.1)
    Another option to get your bean in code: make your com.mycompany.ClientOfTheBusinessObject to implement the ApplicationContextAware interface and then call context.getBean("clientBean")

    0 讨论(0)
  • 2021-01-14 17:31

    I did it using Annotations based configuration:

    1. I did create my BusinessObject class as a POJO and annotate it this way:

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

      I gave it a specific name and did mark it as prototype so that Spring doesn't create a singleton instance for it; every time the bean is required, Spring would create a new instance.

    2. In my @Configuration class (or in the @SpringBootApplication class, if using Spring Boot) I created a CommonsPool2TargetSource instance to hold BusinessObject instances:

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

      Here I'm indicating that the pool will hold BusinessObject instances. Notice that my maxPoolSize=? value is set with the max number of BusinessObject instances I want to hold in the pool.

    3. Finally, I did access my pooled instances this way:

      @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);
          }
      }
      

      It is very important to always make sure to release the BusinessObject borrowed from the pool, without mattering if the business logic did finish successfully or with error. Otherwise the pool could get empty with all the instances being borrowed and never released and any further requests for instances will block forever.

    0 讨论(0)
提交回复
热议问题