0

x 分ごとに、新しいインスタンスをクエリして結果をキャッシュしたいと考えています。現在、単純なキャッシュ ソリューションしか必要ないためSet@ApplicationScoped CacheBean

私は試しました:

ScheduledExecutorService scheduler = Executors
        .newScheduledThreadPool(1);
    ScheduledFuture<?> sf = scheduler.scheduleAtFixedRate(new Runnable() {
        public void run() {
//.................

しかし、作成されたスレッドはコンテキスト インスタンス (InvocationException) にアクセスできませんでした。

では、CDI/JPA の方法でこれを行うにはどうすればよいでしょうか。

Tomcat 7、Weld、JPA2 - Hibernate を使用。

4

3 に答える 3

2

CDI と JPA がすでに統合されている Tomcat のバージョン ( TomEE ) を試すことをお勧めします。OpenJPA に付属していますが、Hibernate を使用できます。次に、次のようなクラスでキャッシュを行います。

@Singleton
@Startup
public class CachingBean {

    @Resource 
    private BeanManager beanManager;

    @Schedule(minute = "*/10", hour = "*")
    private void run() {
        // cache things
    }
}

このコンポーネントは、アプリの起動時に自動的に起動し、上記のメソッドを 10 分ごとに実行します。詳細については、スケジュールのドキュメントを参照してください。

アップデート

あなたのために例をハックしました。優れた CDI/EJB の組み合わせを使用して、CDI イベントをスケジュールします。

事実上、これはミックスBeanManager.fireEvent(Object,Annotations...)に追加するメソッドの単純なラッパーです。ScheduleExpression

@Singleton
@Lock(LockType.READ)
public class Scheduler {

    @Resource
    private TimerService timerService;

    @Resource
    private BeanManager beanManager;

    public void scheduleEvent(ScheduleExpression schedule, Object event, Annotation... qualifiers) {

        timerService.createCalendarTimer(schedule, new TimerConfig(new EventConfig(event, qualifiers), false));
    }

    @Timeout
    private void timeout(Timer timer) {
        final EventConfig config = (EventConfig) timer.getInfo();

        beanManager.fireEvent(config.getEvent(), config.getQualifiers());
    }

    // Doesn't actually need to be serializable, just has to implement it
    private final class EventConfig implements Serializable {

        private final Object event;
        private final Annotation[] qualifiers;

        private EventConfig(Object event, Annotation[] qualifiers) {
            this.event = event;
            this.qualifiers = qualifiers;
        }

        public Object getEvent() {
            return event;
        }

        public Annotation[] getQualifiers() {
            return qualifiers;
        }
    }
}

それを使用するにはScheduler、EJB としてインジェクトし、スケジュールを設定します。

public class SomeBean {

    @EJB
    private Scheduler scheduler;

    public void doit() throws Exception {

        // every five minutes
        final ScheduleExpression schedule = new ScheduleExpression()
                .hour("*")
                .minute("*")
                .second("*/5");

        scheduler.scheduleEvent(schedule, new TestEvent("five"));
    }

    /**
     * Event will fire every five minutes
     */ 
    public void observe(@Observes TestEvent event) {
        // process the event
    }

}

完全なソース コードと動作例は、こちら.

あなたは知らなければならない

  • CDI イベントはマルチトレッドではありません

10 人のオブザーバーがあり、それぞれの実行に 7 分かかる場合、1 つのイベントの合計実行時間は 70 分です。そのイベントが 70 分よりも頻繁に発生するようにスケジュールしても、まったく役に立ちません。

あなたがした場合はどうなりますか?ポリシー@Singleton @Lockによる

  • @Lock(WRITE)がデフォルトです。このモードでは、timeoutメソッドは基本的に、前の呼び出しが完了するまでロックされます。70分ごとに1つしか処理できない場合でも、5分ごとに起動すると、最終的にプールされたすべてのタイマースレッドがシングルトンで待機することになります。
  • @Lock(READ)メソッドの並列実行を可能にしtimeoutます。しばらくの間、イベントが並行して発生します。ただし、実際にはそれぞれ 70 分かかるため、上記と同様に、1 時間ほどでタイマー プールのスレッドが不足します。

洗練された解決策は、使用してから、メソッドの@Lock(WRITE)ように短いタイムアウトを指定することです。次の 5 分間の呼び出しがトリガーされると、あきらめる前にシングルトンへのアクセスを取得するまで 1 分まで待機します。これにより、タイマー プールがバックアップされたジョブでいっぱいになるのを防ぐことができます。「オーバーフロー」は単純に破棄されます。@AccessTimeout(value = 1, unit = TimeUnit.MINUTES)timeout

于 2012-10-18T04:53:37.247 に答える
0

David Blevins としばらくおしゃべりした後、私は彼の答えが私が投票した素晴らしいものであると認めることができます。そのすべてに感謝します。David とはいえ、あなたは TomEE への関与を発表するのを忘れていました。

とにかく、私が行った解決策は、#Deltaspike (freenode) で Mark Struberg によって提案されました。

デルタスパイクのユーザーとして、私はデルタスパイクでそれを行うことができてうれしく思いました. ソリューションは、このブログ投稿で概説されています。

http://struberg.wordpress.com/2012/03/17/controlling-cdi-containers-in-se-and-ee/

https://issues.apache.org/jira/browse/DELTASPIKE-284を参照して、OWB に切り替える必要がありました。

乾杯

于 2012-10-21T08:48:18.170 に答える
0

new Runnable() {....} を scheduler.scheduleAtFixedRate に渡す代わりに、Runnable を実装する CDI Bean を作成し、その Bean を @Inject してから scheduler.scheduleAtFixedRate に渡します。

于 2012-10-19T06:31:37.803 に答える