Skip to content

Regression with poolTargetSource and scoped proxy [SPR-15042] #19608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Dec 22, 2016 · 6 comments
Closed
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: regression A bug that is also a regression
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Dec 22, 2016

Janne Valkealahti opened SPR-15042 and commented

It seems that this which is pretty much straight from docs works with 4.3.3 but not with 4.3.4, 4.3.5 or 5.0.0.BUILD-SNAPSHOT.

@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public ProxyFactoryBean myObject() {
	ProxyFactoryBean pfb = new ProxyFactoryBean();
	pfb.setTargetSource(poolTargetSource());
	return pfb;
}

@Bean
public CommonsPool2TargetSource poolTargetSource() {
	CommonsPool2TargetSource pool = new CommonsPool2TargetSource();
	pool.setMaxSize(3);
	pool.setTargetBeanName("myObjectTarget");
	return pool;
}

@Bean(name = "myObjectTarget")
@Scope(scopeName="prototype")
public Object myObjectTarget() {
	return new Object();
}
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myObject' defined in BeanDefinition defined in com.example.ScopeConfiguration: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.myObject': Target type could not be determined at the time of proxy creation.
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:577)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:484)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	at org.springframework.beans.factory.support.AbstractBeanFactory.isSingleton(AbstractBeanFactory.java:424)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:419)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:385)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:503)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.getSinglePropertySourcesPlaceholderConfigurer(ConfigurationPropertiesBindingPostProcessor.java:259)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.deducePropertySources(ConfigurationPropertiesBindingPostProcessor.java:238)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.afterPropertiesSet(ConfigurationPropertiesBindingPostProcessor.java:202)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1668)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1605)
	... 59 more
Caused by: java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.myObject': Target type could not be determined at the time of proxy creation.
	at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:96)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1628)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1596)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:568)
	... 73 more

Affects: 4.3.4

Reference URL: spring-attic/spring-framework-issues#144

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Janne Valkealahti, what is this setup trying to accomplish to begin with? A request-scoped ProxyFactoryBean which in turn delegates to a pooled target source? What's the benefit here over a simple shared proxy for such a shared target source, i.e. simply dropping @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) from the ProxyFactoryBean definition?

@spring-projects-issues
Copy link
Collaborator Author

Janne Valkealahti commented

This is coming from my Spring Statemachine samples which originated from a question - "If using machines in a controller methods how can you avoid instantiation of a machine(which is relatively expensive) with every request and re-use a pooled set of machines with a request scope".

StateMachineConfig
StateMachineController

What I did in that sample was only way to get pooling working. Thought, if there is better way to accomplish same logic I'd also be fine to change my sample.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Well, what the above code actually declares is a request-scoped proxy object (or even worse, a request-scoped proxy factory object) which - for every method invocation - grabs a fresh object from the target pool to delegate to, releasing it right after each method call. You'll have a per-request proxy object but you won't get any request-specific state or other benefit out of such a request-scoped proxy, as far as I can see, so you could just drop that scoping at the proxy level and use a plain shared proxy to the pool.

If you rather need a stateful instance from the pool associated for the lifetime of a request, then such AOP TargetSource pooling - with its per-method-call semantics - isn't the right choice to begin with. You'd rather have to craft some custom code which grabs an instance from a pool at the beginning of a request and releases it back to the pool at the very end of each request. Modelling such a stateful object as a request-scoped bean makes sense, simply grabbing the delegate from the pool in an init method and releasing it back to the pool in a destroy method. There is no AOP involved then, just a request-scoped bean instance which happens to grab a delegate from a shared pool.

That said, I'm still researching where we got a regression here: I suppose we previously simply accepted to scope the ProxyFactoryBean object - as semantically bogus as this was - so maybe we should restore that ability just for the sake of making such a declaration work (even if it is probably not what the user really needs).

@spring-projects-issues
Copy link
Collaborator Author

Janne Valkealahti commented

Thanks for clarifying this, I always felt that I might have been doing something stupid in that sample. I'll play with those ideas you wrote!

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 28, 2016

Juergen Hoeller commented

This turns out to be another side effect of the change behind #19382, along with #19458. Fixed for 4.3.6 now.

My recommendation still stands that the scenario is flawed :-) Nevertheless, such a setup should start up cleanly which it does again.

@spring-projects-issues
Copy link
Collaborator Author

Janne Valkealahti commented

Thanks a lot! Now my stuff builds fine on latest framework/boot snapshots. I'll definitely get that sample fixed for something better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: regression A bug that is also a regression
Projects
None yet
Development

No branches or pull requests

2 participants