2

我有以下控制器和服务

@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 实例注入控制器以进行不同的连接。

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

我可以通过使用使其工作:

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

我只是想知道如何在春天做到这一点。

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

编辑:通过使用以下代码和 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;
}

}

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

4

1 回答 1

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 的两个方法时:

    我的服务.foo(); myService.bar(); // 你真的想要一个新的bean吗?

PS:如果您使用 Spring < 3.1.2,您将需要指定 bean 的 ID,因为getBean(Class<?> type)这些版本非常慢。

于 2012-08-16T14:03:56.763 回答