spring中如何配置CommonsPool2TargetSource? [英] How to configure CommonsPool2TargetSource in spring?

查看:101
本文介绍了spring中如何配置CommonsPool2TargetSource?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这让我脖子痛!!!我有三个查询.

This become pain in my neck!!! I have three queries.

1)我想在我的项目中配置 CommonsPool2TargetSource 以汇集我的自定义 POJO 类.

1)I want to configure CommonsPool2TargetSource in my project for pooling of my custom POJO class.

到目前为止我做了什么:

MySpringBeanConfig 类:

MySpringBeanConfig class :

    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackages = {"com.redirect.controller","com.redirect.business","com.redirect.dao.impl","com.redirect.model"})
    @EnableTransactionManagement
    @PropertySource("classpath:" + JioTUConstant.SYSTEM_PROPERTY_FILE_NAME + ".properties")
    @Import({JioTUCouchbaseConfig.class,JioTUJmsConfig.class})
    public class JioTUBeanConfig extends WebMvcConfigurerAdapter {
          private static final Logger LOGGER = Logger.getLogger(JioTUConfig.class);

          @Bean
          public CommonsPool2TargetSource poolTargetSource() {
               CommonsPool2TargetSource commonsPool2TargetSource = new CommonsPool2TargetSource();
               commonsPool2TargetSource.setTargetBeanName("jioTUURL");
               commonsPool2TargetSource.setMinIdle(5);
               commonsPool2TargetSource.setMaxIdle(5);
               commonsPool2TargetSource.setMaxSize(10);
               return commonsPool2TargetSource;
           }

           @Bean
           public ProxyFactoryBean proxyFactoryBean() {
               ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
               proxyFactoryBean.setTargetSource(poolTargetSource());
               return proxyFactoryBean;
           }

           @Bean
           public MethodInvokingFactoryBean poolConfigAdvisor() {
               MethodInvokingFactoryBean poolConfigAdvisor = new MethodInvokingFactoryBean();
               poolConfigAdvisor.setTargetObject(poolTargetSource());
               poolConfigAdvisor.setTargetMethod("getPoolingConfigMixin");
               return poolConfigAdvisor;
           }
   }

我在 "com.redirect.model" 包中的 POJO 类:

My POJO class inside "com.redirect.model" package:

@Repository
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Document
public class JioTUURL{

    @Id
    private String keyword;

    @Field
    private String url;

    @Field
    private String title;

    @Field
    private String timestamp;

    @Field
    private String ip;

    @Field
    private Integer clicks;

    @Field
    private String user;

    //Getter/Setter

}

异常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException:否定义了 [com.redirect.model.JioTUURL] 类型的合格 bean:预期单个匹配 bean,但发现 2:jioTUURL,proxyFactoryBean

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.redirect.model.JioTUURL] is defined: expected single matching bean but found 2: jioTUURL,proxyFactoryBean

仅供参考,我没有为 JioTUURL 明确定义任何 bean.就看spring的@ComponentScan了

FYI I have not define any bean for JioTUURL explicitly. It is up to the @ComponentScan of spring

如果我注释以下行,在 JioTUConfig.java 类的 proxyFactoryBean() 方法内

If I comment the following line, inside proxyFactoryBean() method of JioTUConfig.java class

    @Bean
    public ProxyFactoryBean proxyFactoryBean() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//        proxyFactoryBean.setTargetSource(poolTargetSource());
        return proxyFactoryBean;
    }

然后它运行良好,日志信息如下

then it is running fine with log information as below

09-08-2016 16:28:13.866|INFO |localhost-startStop-1|Bean'poolTargetSource' 类型 [classorg.springframework.aop.target.CommonsPool2TargetSource] 不是有资格被所有 BeanPostProcessor 处理(例如:没有资格自动代理)|[PostProcessorRegistrationDelegate.java:328]

09-08-2016 16:28:13.866|INFO |localhost-startStop-1|Bean 'poolTargetSource' of type [class org.springframework.aop.target.CommonsPool2TargetSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)|[PostProcessorRegistrationDelegate.java:328]

2)如何从池中获取对象?

2)How to fetch objects from pool?

@Controller
public class JioTUController {

    private static final Logger LOGGER = Logger.getLogger(JioTUController.class);
    @Autowired
    private JioTUCommonBusiness jioTUCommonBusiness;
    @Autowired
    private ObjectFactory<JioTUURL> jioTUURLObjectFactory;//Need to replace I guess

    public JioTUController() {
         LOGGER.info("Loading JioTUController complete");
    }
    @RequestMapping(method = RequestMethod.GET, value="/*")
    public ModelAndView postDataAsJSON(HttpServletRequest request,HttpServletResponse response, ModelAndView modelAndView) {

            //Should be replace with code that fetch object for me from the pool
            JioTUURL jioTUURL = jioTUURLObjectFactory.getObject();

            //App Business
    }
}

3)池中的那些对象是被回收还是会在每个 HTTP 请求服务后重新实例化?

3)Is those objects in pool recycled or is going to re-instantiate after each HTTP request served?

推荐答案

我遇到了同样的问题,并重现了一个似乎有效的简单案例.我想现在帮助您为时已晚,但我希望它可以帮助未来的读者.

I've been confronted to the same problem and have reproduced a simple case that seems to be working. I suppose it is too late to help you, but I hope it might help future readers.

您必须配置三个元素:

  • 您正在合并的原始 bean.当然,您需要指定 prototype 范围.
  • CommonsPool2TargetSource,它将需要您刚刚配置的原型 bean 的名称.
  • 一个 ProxyFactoryBean,它将使用刚刚配置的 TargetSource.
  • The original bean, that you are pooling. Naturally, you will need to specify the prototype scope.
  • The CommonsPool2TargetSource, which will require the name of the prototype bean you just configured.
  • A ProxyFactoryBean that will use the just configured TargetSource.
import org.keyboardplaying.bean.Foo;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.AbstractPoolingTargetSource;
import org.springframework.aop.target.CommonsPool2TargetSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class PoolConfiguration {

    // The targetBeanName is mandatory for CommonsPool2TargetSource. Rather use a constant to avoid mistakes.
    private static final String FOO_TARGET_NAME = "fooTarget";

    /**
     * Returns the pooled bean.
     * 
     * @return the pooled bean
     */
    @Bean(FOO_TARGET_NAME)
    // Remember to make this bean a prototype
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Foo fooTarget() {
        return new Foo();
    }

    /**
     * Returns the pool.
     * 
     * @return the pool
     */
    @Bean
    public TargetSource fooSource(
        // You probably would externalize this value to your application.properties
        @Value("2") int maxSize
    ) {
        final AbstractPoolingTargetSource poolingConfig = new CommonsPool2TargetSource();
        poolingConfig.setMaxSize(maxSize);
        // The targetBeanName is mandatory
        poolingConfig.setTargetBeanName(FOO_TARGET_NAME);
        return poolingConfig;
    }

    /**
     * Returns a ProxyFactoryBean that is correctly pooled.
     * 
     * @return the proxy we will call
     */
    @Bean
    public ProxyFactoryBean foo(TargetSource fooSource) {
        ProxyFactoryBean proxyBean = new ProxyFactoryBean();
        proxyBean.setTargetSource(fooSource);
        return proxyBean;
    }
}

快速测试

我的 Foo bean 非常简单.它在创建时与 ID 相关联,并在日志记录时简单地记录.

Quick test

My Foo bean is quite simple. It is associated to an ID on creation and simply logs it on logging.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class Foo {

    public static final long SLEEP_PERIOD = 1000L;

    private static final AtomicInteger COUNTER = new AtomicInteger();
    private static final Logger LOG = LoggerFactory.getLogger(Foo.class);

    private final int instanceNumber;

    public Foo() {
        this.instanceNumber = COUNTER.incrementAndGet();
    }

    public void call() {
        LOG.warn(">>>>>>>>>>> Called instance {}", instanceNumber);
        try {
            Thread.sleep(SLEEP_PERIOD);
        } catch (InterruptedException e) {
            LOG.error(e.getMessage(), e);
        }
    }
}

这是一个(脏)类,可以在并行线程中多次运行此 bean.

Here is a (dirty) class to run this bean several times, in parallel threads.

import org.keyboardplaying.bean.Foo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PoolConfigurationTest {

    @Autowired
    private ApplicationContext context;

    @Test
    public void test() {
        final Runnable runnable = () -> {
            // Note: the name is required as both "foo" and "fooTarget" will match class Foo.
            final Foo foo = (Foo) context.getBean("foo");
            foo.call();
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
        runnable.run();
    }
}

如果您查看下面的日志,您会发现我们只使用了两个实例(对应于我设置的 maxSize).当两个实例都在使用时,下一个线程必须等待前面的处理结束,因此日志中会暂停 1 秒(Foo 的睡眠时间).

If you have a look at the log below, you'll see we use only two instances (corresponding to the maxSize I set). When both instances are in use, the next threads have to wait for the previous processings to be over, hence a pause of 1 s (the sleep time of Foo) in the logs.

14:30:59.624  WARN [    main] Foo: >>>>>>>>>>> Called instance 1
14:30:59.624  WARN [Thread-4] Foo: >>>>>>>>>>> Called instance 2
14:31:00.626  WARN [Thread-5] Foo: >>>>>>>>>>> Called instance 2
14:31:00.626  WARN [Thread-3] Foo: >>>>>>>>>>> Called instance 1

这篇关于spring中如何配置CommonsPool2TargetSource?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆