问题描述
这让我脖子痛!!!我有三个查询.
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
仅供参考,我没有为 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]
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 configuredTargetSource
.
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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!