将不同的服务实例注入控制器

时间:2012-08-16 13:51:12

标签: spring model-view-controller code-injection autowired

我有以下控制器和服务

@Controller
public class MyController
{
   @Autowired
   private MyService myService;

  @RequestMapping(method=RequestMethod.GET, value="/connect.do")
  public String connect(Model model)
  {
    invokeService();
    return  "xxx";
  }

  private void invokeService()
  {
        myService.test();
  }

}


@Service
public class MyService
{
 private int value1 = 200;
 private int value2 = 333;
 private String value3 ;
 private String value4 ;
 private String value5 ;
 ....

 public void test()
 {
        System.out.println(value1++);
        foo();
  }

 private void foo()
 {

 }

}

当我使用2个浏览器连接到应用程序时,输出为" 200"和" 201",这意味着Spring将相同的MyService实例注入控制器以进行不同的连接。

我需要输出为" 200"和" 200"当我使用2个不同的连接来访问应用程序时,因为我需要在" test()"之间共享values1,values2,value3等。和" foo()"。怎么在春天做?基本上,我希望Spring为不同的连接注入不同的实例。我在Service bean中尝试了@Scope(" prototype")但它没有用。

我可以通过使用:

使其工作
@Controller
public class MyController
{
    private void invokeService()
   {
        new MyService.test();
   }
}

我只是想知道如何在Spring中这样做。

提出这个问题的另一种方法是:如何拥有多个控制器实例(每个用户连接一个)而不是一个服务于所有连接的控制器实例?

编辑:我可以通过使用以下代码和2个浏览器连接看到原型(输出:200 200 200 200)和单件(输出:200 201 202 203)的区别

private void invokeService() 
{ 
  myService = applicationContext.getBean( MyService.class ); 
  new MyService.test();
  myService = applicationContext.getBean( MyService.class ); 
  new MyService.test(); 
} 

但是当我把" applicationContext.getBean(MyService.class)"而在postConstructor中:

public class MyController implements ApplicationContextAware {

private SearchService searchService;

@PostConstruct
public void init() {
    searchService = applicationContext.getBean( SearchService.class );
}

protected ApplicationContext applicationContext;

@Override
public void setApplicationContext( ApplicationContext applicationContext ) throws BeansException {
    this.applicationContext = applicationContext;
}

}

并使用" @Scope(BeanDefinition.SCOPE_PROTOTYPE)"在MyService上,输出仍然是" 200"和" 201"当我使用2个浏览器连接到应用程序时

1 个答案:

答案 0 :(得分:2)

@Autowired不会与@Scope("prototype")混合启用代理生成(这可能不是您想要的 - 它会很快变得复杂)。

改为MyController ApplicationContextAware

public class MyController implements ApplicationContextAware {

    public MyService getMyService() {
        return applicationContext.getBean( MyService.class );
    }

    protected ApplicationContext applicationContext;

    @Override
    public void setApplicationContext( ApplicationContext applicationContext ) throws BeansException {
        this.applicationContext = applicationContext;
    }

}

现在@Scope(BeanDefinition.SCOPE_PROTOTYPE)将按预期工作。

请注意,每次致电MyService时,您都会获得getMyService()的新实例。

为什么你的方法(和我的旧方法)不起作用? MyController是一个单例,因此字段myService只连接一次 - 每次访问字段时Spring都不会给你一个新的bean实例,原因有两个:

  1. 这意味着Spring必须分析类的字节代码,以找到代码访问该字段的所有位置。
  2. 它会以其他方式破裂。例如,当您调用bean的两个方法时:

    myService.foo();    myService.bar(); //你真的想要一个新豆吗?

  3. PS:如果你使用Spring&lt; 3.1.2,您将需要指定bean的ID,因为getBean(Class<?> type)对于这些版本来说非常慢。