Closed
Description
Bob Tiernay opened SPR-9852 and commented
The attached test case demonstrates that @Resource
of injection of singleton in prototype using AnnotationConfigApplicationContext is not thread-safe. However, changing @Resource
to @Autowired
seems to resolve the issue.
Please see http://stackoverflow.com/questions/12700239/thread-safety-of-calling-bean-methods-from-returned-annonymous-inner-classes/12700284#comment17146235_12700284 for more details
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.pentaho.di.core.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.oanda.bi.rm.test.AnnotationCallableConfigTest.Config;
/**
* @see http://stackoverflow.com/questions/12700239/thread-safety-of-calling-bean-methods-from-returned-annonymous-inner-classes/12700284#comment17146235_12700284
* @see http://forum.springsource.org/showthread.php?130731-Thread-safety-of-calling-Bean-methods-from-returned-annonymous-inner-classes&p=426403#post426403
* @author btiernay
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Config.class }, loader = AnnotationConfigContextLoader.class)
public class AnnotationCallableConfigTest {
@Autowired
Callable<Holder> callable;
@Test
public void test() throws InterruptedException, ExecutionException {
final int threads = 10;
ExecutorService service = Executors.newFixedThreadPool( threads );
List<Future<Holder>> futures = new ArrayList<>();
for ( int i = 0; i < threads; i++ ) {
futures.add( service.submit( callable ) );
}
service.shutdown();
service.awaitTermination( 1, TimeUnit.MINUTES );
for ( Future<Holder> future : futures ) {
final Holder holder = future.get();
Assert.assertNotNull( holder.value );
}
}
public static class Holder {
// Changing this to @Autowired makes the test pass
@Resource(name = "singleton")
protected Integer value;
}
@Configuration
public static class Config {
@Bean
public Integer singleton() {
return 1;
}
@Bean
@Scope("prototype")
public Holder prototype() {
return new Holder();
}
@Bean
public Callable<Holder> function() {
return new Callable<Holder>() {
@Override
public Holder call() {
return prototype();
}
};
}
}
}
Affects: 3.1.2
Issue Links:
- Autowired properties can remain unset during concurrent instantiation of prototype-beans [SPR-9806] #14439 Autowired properties can remain unset during concurrent instantiation of prototype-beans
- Regression: scoped beans being cached too aggressively [SPR-9627] #14261 Regression: scoped beans being cached too aggressively
Metadata
Metadata
Assignees
Type
Projects
Relationships
Development
No branches or pull requests
Activity
spring-projects-issues commentedon Oct 4, 2012
Juergen Hoeller commented
This very much looks like a variation of #14439 and seems to be covered by that fix already. In any case, your test consistently passes for me after that fix.
Juergen