Is Spring @autowired not meant for non-singleton containers?

后端 未结 4 1321
滥情空心
滥情空心 2020-12-14 19:21

I have a MyTask class which implements Runnable and there can be many such objects instantiated at any given moment. There are certain properties t

4条回答
  •  青春惊慌失措
    2020-12-14 20:20

    Typically adding @Scope("prototype") should not cause null error for autowired blah bean,you should check how you instantiate MyTask bean. I think the problem is that you manually instantiate MyTask like:

       MyTask task = new MyTask();
    

    and therefor it goes out of Spring's control that is why its dependency, blah bean, is null , instead of manual instantiation, you need to autowire it and let Spring takes care of its dependencies then blah willnot be null. But then there is another issue. Autowiring a prototype bean, MyTask, whithin another singleton object is wrong. Spring container creates a singleton bean only once, and thus only sets the prototype bean once and this causes the prototype scope not to work.Like below, Myactivity is a singleton which autowires MyTask, I also added a constructor for MyTask to print something once a new instance of MyTask gets created. In below case it only prints once, therefore prototype is not working.

    @Component
    @Scope("prototype")
    public class MyTask implements Runnable {
    
      @Autowired
      public SomeSpecialSpringConfiguredConnectionClass blah;
    
      public MyTask(){
        System.out.println("New Instance of MyTask");
      }
    
      @Override
      public void run() {
        assert(blah != null);
      }
    }
    
    
    @Component
    public class MyActivity {
    
      @Autowired
      private MyTask task;
    
      public MyTask start() {
        return task;
      }
    }
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = {MyActivity.class, MyTask.class, 
       SomeSpecialSpringConfiguredConnectionClass.class})
    public class MyTaskTest {
    
      @Autowired
      private MyActivity activity;
    
      @Test
      public void testActivity() {
        for (int i = 0; i < 5; i++) {
            MyTask task = activity.start();
            task.run();
        }
      }
     }
    

    Based on Spring AOP Scoped proxies I changed @Scope("prototype") to @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype") so the scoped proxy injects a new instance of MyTask every time singleton MyActivity bean gets called.

    @Component
    @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")
    public class MyTask implements Runnable {
    
      @Autowired
      public SomeSpecialSpringConfiguredConnectionClass blah;
    
      public MyTask(){
        System.out.println("New Instance of MyTask");
      }
    
      @Override
      public void run() {
        assert(blah != null);
      }
    }
    

    and now the prototype is working fine and this was the result printed in console:

    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    New Instance of MyTask
    

提交回复
热议问题