web-dev-qa-db-ja.com

Javaサーブレットコンテキストでグローバルオブジェクトを取得および設定する方法

誰かがアドバイスできるかどうか疑問に思います:Quartzによって実行されているスケジュールされたジョブがオブジェクトの配列リストを毎時間更新するシナリオがあります。

しかし、私はこのオブジェクトの配列リストがTomcatによって作成されたすべてのセッションから見えるようにする必要があります。したがって、私が考えているのは、このオブジェクトを、実行されるQuartzジョブから1時間ごとにどこかに書き込み、各セッションがアクセスできるようにすることです。

誰がこれがどのようにして最良に達成されるかを言うことができますか? Quartzジョブからサーブレットコンテキストにオブジェクトが書き込まれることについて疑問に思っていましたか?別の方法として、各セッションでデータベーステーブルからオブジェクトの配列リストを生成します。

ありがとう

モーガンさん。

21
Mr Morgan

はい、リストをアプリケーションスコープの属性としてServletContextに保存します。代わりにデータベースからデータを取得するのは、リストを1時間ごとに更新するだけなので、おそらくあまり効率的ではありません。 QuartzタスクにServletContextListenerオブジェクトへの参照を提供するには、ServletContextの作成が必要になる場合があります。 ServletContextは、サーブレットやリスナーなどのJavaEE関連のクラスからのみ取得できます。

編集:ServletContextListenerでは、ジョブを作成するときに、JobDataMapに追加することでリストをジョブに渡すことができます。

public class MyServletContextListener implements ServletContextListener{
  public void contextInitialized(ServletContextEvent event){
    ArrayList list = new ArrayList();

    //add to ServletContext
    event.getServletContext().setAttribute("list", list);

    JobDataMap map = new JobDataMap();
    map.put("list", list);
    JobDetail job = new JobDetail(..., MyJob.class);
    job.setJobDataMap(map);
    //execute job
  }

  public void contextDestroyed(ServletContextEvent event){}
}

//Quartz job
public class MyJob implements Job{
  public void execute(JobExecutionContext context){
    ArrayList list = (ArrayList)context.getMergedJobDataMap().get("list");
    //...
  }
}
15
Michael

EhCache などのキャッシュソリューションを試して値を保存し、1時間ごとに更新することができます。並行性の問題を処理します。キャッシュオブジェクト自体はServletContextに保存できます

QuartzジョブからServletContextに書き込む良い方法は、変更された値について通知を受けるリスナーをジョブに登録することです。だから例えば:

public class JobListener {
    public void updateValue(Object newValue);
}

public class ServletContextCacheJobListener implements JobListener {
     private ServletContext ctx;
     public ServletContextJobListener(ServletContext ctx) {
         this.ctx = ctx;
     }

     public void updateValue(Object newValue) {
          Cache cache = (Cache) ctx.getAttribute("cache");
          cache.update("yourKey", newValue);
     }
}

あなたの仕事はList<JobListener>そして、ジョブをスケジュールするときに、具象リスナーをインスタンス化し、それをジョブに追加します。

1
Bozho

まあ、あなたが静的フィールドを使用する場合、それらは同じクラスローダーによってロードされたすべてのクラスから見えるでしょう。私は、少なくとも1つのアプリのサーブレットが最終的には適格になると思います。しかし、これは確かに汚いです。

(より)グローバルであることが定義され、保証されているオブジェクトは ServletContext です。これは、1つのアプリケーションの一部を形成するすべてのサーブレット間で共有されます。つまり、同じweb.xmlからロードされます。 ServletContextにはputgetの呼び出しがあり、基本的にはMapとして扱うことができます。

さらに、1つのTomcatサーバー内のすべてのWebアプリに共通するクラスを見つける必要があります。 Tomcatはローダーを使って多くのフットワークを行っており、異なるWebアプリには異なるローダーがあると思います。これを回避するには、独自のクラスを作成し、そのクラスをTomcatのcommonまたはsharedディレクトリに配置します。 この説明 を正しく理解していれば、それらのクラスはすべてのWebアプリで利用可能になります。

最後に、単一のTomcatサーバーの範囲を超えて、JVM間で通信するためのTCP/IPベースのメカニズムが必要になります。しかし、私はあなたの質問を理解したように、それは必要ではないはずです。

0
Carl Smotricz