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インスタンスをコントローラーに注入することを意味します。

「test()」と「foo()」の間でvalues1、values2、value3などを共有する必要があるため、アプリケーションにアクセスするために2つの異なる接続を使用する場合、出力は「200」と「200」である必要があります。春にそれを行う方法は?基本的に、Springに異なる接続に対して異なるインスタンスを注入してもらいたいです。Service Beanで@Scope( "prototype")を試しましたが、機能しません。

私はそれを使用して動作させることができます:

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

春にどうやってやるのか気になります。

この質問をする別の方法は次のとおりです。すべての接続に1つのコントローラーインスタンスを提供するのではなく、複数のコントローラーインスタンス(ユーザー接続ごとに1つ)を作成するにはどうすればよいですか。

編集:次のコードと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(); 
} 

しかし、代わりにpostConstructorに「applicationContext.getBean(MyService.class)」を配置すると、次のようになります。

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は 1 回だけ接続されます。Spring は、次の 2 つの理由により、フィールドにアクセスするたびに Bean の新しいインスタンスを提供できません。

  1. これは、コードがフィールドにアクセスするすべての場所を見つけるために、Spring がクラスのバイト コードを分析する必要があることを意味します。
  2. それは他の方法で壊れるでしょう。たとえば、Bean の 2 つのメソッドを呼び出す場合:

    myService.foo(); myService.bar(); //本当にここに新しい Bean が必要ですか?

PS: Spring < 3.1.2 を使用する場合、getBean(Class<?> type)これらのバージョンでは非常に遅いため、Bean の ID を指定する必要があります。

于 2012-08-16T14:03:56.763 に答える