たまには日記の一つでも。

28にしてはじめたバイオリンの記録と、ときどき日曜ハッキング

Actionクラスの中からバックグラウンドタスクを起動する

ActionクラスであるMainActionBeanクラスから、BackgroundTaskBean.execute()をバックグラウンドで実行したい場合。最初は普通に子スレッドを生成してやろうとしてたのですが、何やらEJBの中ではスレッド生成しちゃダメだとかなんとか。EJB3もそうなんでしょうか?
さておき、安全のため代替として下記の方法をとりました。ヒントはSeamリファレンスマニュアルのChapter17、Asynchronicity and messaging。バックグラウンドタスクを外部システム上で実行するなら、JMS使えばいいんでしょうけど、ローカルだけだとさすがに大げさですし。


MainActionインターフェースは省略するとして、MainActionBean.java

@Stateless
@Name("mainAction")
public class MainActionBean implements MainAction {
    @In(create=true)
    private BackgroundTask backgroundTask;

    public void execute() {
        ...
        // 即座にreturnし、中身の処理はバックグランドで実行される
        backgroundTask.execute();
    }
}


BackgroundTask.java

@Local
public interface BackgroundTask {
    @Asynchronous
    public void execute();
}


BackgroundTaskBean.java

@Stateless
@Name("backgroundTask")
public class BackgroundTaskBean implements BackgroundTask {
    public void execute() {
        ...
        Process someProcess = Runtime.getRuntime().exec(someCmd);
        ...
    }
}

BackgroundTaskBeanのsetterでインスタンスフィールドを設定しても、その後execute()で実行するときには、フィールドはnullになってました。仕方ないので、execute()の引数で全て渡すようにしてます。まだ仕組みは追えてないのですが、タイマーで実行される前に、一度インスタンスプールに戻されて初期化される、ということなのでしょうか?
とりあえず、手元ではそんな感じで最低限の用は足せてます。もしもっとエレガントな解法をご存知の方いらっしゃいましたら、是非教えてくださいまし。