5

スプリングMVCとスレッドセーフについて質問があります。

Tomcatに保存されるWebアプリケーションを開発しています。私が正しく理解していれば、Tomcatはリクエストごとにスレッドを作成し、スレッドプールがあります。現在、ディスパッチャサーブレットはリクエスト間で共有されており、おそらくスレッドセーフです。

しかし、私がこのようなコントローラーを作成すると、次のようになります。

@Controller
@RequestMapping("/manage")
public class QuestionManagementController {

彼はSingletonスコープを持っているので、すべてのユーザーからのすべてのリクエストで同じコントローラーが使用されます。

私はこの問題が通常どのように解決されるのか疑問に思っています:

1:コントローラーはSessionスコープで作成されていますか?(ただし、1人のユーザーがコントローラーの競合状態につながる可能性のあることをすばやく実行すると、問題が発生する可能性もあると思います)。

2:コントローラーのスコープは次のとおりですrequest

3:クラスレベルで変数を共有しない、または読み取り専用モードにするステートレスコントローラーを作成する

または、この種の問題を解決するためのより良い「ベストプラクティス」があるかもしれません。

私はこの質問をしています。これは、スコープが設定されSingletonており、ほとんどのメソッドでデータベース内のユーザーをクエリしているため、スコープが原因でこの情報をクラスレベルの変数に格納できないという問題があるためです。スレッドセーフなコレクションを使用することもできますが、後で同期アクセスを必要とする他のリソースが存在する可能性があります。

4

1 に答える 1

5

問題を回避するために、request、session、principalなどのコントローラーメソッドに多くのパラメーターを追加できます。

通常、3層のアーキテクチャがあります。

  • @Controller(彼らはサービスに委任します)
  • @Service(DAOまたはリポジトリを使用して作業を行います)
  • @Repository(またはDAO、DBアクセスを行います)

したがって、DBでクエリしている内容に応じて、DBにアクセスするのにコストがかかり、DBからのデータが必要になるたびにサービスを呼び出す場合(つまり、コントローラーに何も保存されていない場合)、Springによってキャッシュが注入されるサービスを用意することをお勧めします。クラスレベル)

簡単な例として、Spring-Securityの背後にあり、すべてが完全にログインしたユーザーを必要としているとしましょう。userDataキーがユーザーログインであるテーブルがあり/data、ユーザーデータを表示するページを取得するためのURLがあります。

@Controller
@RequestMapping("/data")
public class UserDataController
{
    @Autowired
    private UserService userService;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public ModelAndView data(final Principal principal) {
        Assert.notNull(principal); // throw if assertion fails
        Assert.hasText(principal.getName());

        final UserData userData = this.userService.findByUserName(principal.getName());
        Assert.notNull(userData, "userData not found");

        return new ModelAndView("userData", "userData", userData);
    }
}

@Service("userService")
public class userService 
{
    private static final String USERDATA_CACHE = "com.acme.foo.UserData";

    @Autowired
    private UserDataRepository userDataRepository;

    @Cacheable(USERDATA_CACHE)
    public UserData findByUserName(final String userName) {
        return this.userDataRepository.findByUserName(userName);
    }
}

@Repository
public class UserDataRepository
{
    // or use spring-data-jpa

    public UserData findByUserName(final String userName) {
        // query table userData and create an UserData from results.
    }
}

ここではプリンシパルとスプリングを使用して、これが現在のユーザーのものであることを確認します。

参照:

この答えがあなたの懸念に完全に答えるかどうかを確認してください

于 2012-08-25T13:18:31.473 に答える