2

サーブレットで作成された新しいスレッドに、サーブレット/CDI コンテキストが含まれていないことがわかりました。この問題を実験するために、HelloWorld サーブレット (以下を参照) を作成しました。以下の例では、新しいスレッド (FutureTask) で「doIt()」関数を実行していることがわかります。しかし、それは NULL を返しますが、「doIt()」メソッドを直接呼び出すと、BeanManager は NULL ではありません。

/**
 * Servlet implementation class HelloWorld
 */
@WebServlet("/HelloWorld")
public class HelloWorld extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private static Logger logger = Logger.getLogger(HelloWorld.class
            .getName());

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter writer = response.getWriter();

        writer.println("<html>");
        writer.println("<head><title>Hello World Servlet</title></head>");
        writer.println("<body>");
        writer.println("<h1>Context injection into Thread Experiment</h1>");
        try {
            // 1. This is NOT working
            new Thread(testTask).start();
            testTask.get(5000, TimeUnit.SECONDS);

            // 2. This is working
                //doIt();

        } catch (Exception e) {
            e.printStackTrace();
        }

        writer.println("<body>");
        writer.println("</html>");
        writer.close();         
    }

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                doIt();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    FutureTask<Object> testTask = new FutureTask<Object>(runnable, null);

    protected void doIt() throws Exception {
        if(getBeanManager() == null) { 
            throw new Exception( "BEAN MANAGER IS NULL"); 
        }
    }

    public static BeanManager getBeanManager() {
        try {
            InitialContext initialContext = new InitialContext();
            return (BeanManager) initialContext.lookup("java:comp/BeanManager");
        } catch (NamingException e) {
            logger.info("Couldn't get BeanManager through JNDI");
            return null;
        }
    }
}

私はオンラインで検索しましたが、それが可能であると言うよりも良い参考文献を見つけることができませんでした. 誰かが私を助けたり、新しいスレッドにコンテキストを挿入/渡すための良いポインタを提供してくれたりしたら、それは素晴らしいことです。

4

3 に答える 3

6

EJB 3.1 および Java EE 6 以降を使用している場合、メソッドの表記@Asynchronousにより、メソッドは別のスレッドで実行され、リソースの管理などを処理します。

Kalpesh Soni が指摘したように、さらに制御が必要な場合は、Java EE 7 以降を使用している場合、この回答で の使用方法について説明します。ManagedExecutorService

getBeanManager()さらに、その静的メソッドが本当に必要かどうかはわかりません。 @EJB BeanManager beanManager;(または@Inject) だけで十分ではありませんか?

于 2014-08-19T16:06:33.997 に答える
1

リクエストが終了した後、コンテナーはサーブレット オブジェクトをクリーンアップする必要があります。

スレッドは独自のリソースを作成する必要があります

ちなみに、コンテナ (tomcat/weblogic/websphere) を使用する場合、独自のスレッドでは利用できないトランザクション コンテキストをセットアップするために、いくつかの追加処理が行われます。

スレッド API と Java ee を混在させないことが最善です

Java EE仕様とマルチスレッド

于 2014-08-19T15:13:53.487 に答える
0

この質問で尋ねた問題の解決策を追加したいと思います。質問は、ここに記載されている回答の助けを借りて解決されました。この回答は、将来他の開発者に役立つと思います。私の主な目的は、関数のタイムアウトを取得することでした

メソッドで@Asyncronousを使用して、CDI コンテキストも含む別のスレッドで実行しました。を使用して、「 Future.get(timeout, TimeUnit) 」タスクを実行するタスクのタイムアウト パラメータを設定します。

以下は、Helloworld サーブレットのコードで、タスクを実行し、作業を完了するために予想される時間を超えて実行された場合にタイムアウトを取得します。

@WebServlet(value = "/HelloWorld", asyncSupported = true)
public class HelloWorld extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private static Logger logger = Logger.getLogger(HelloWorld.class
            .getName());

    @Inject doItWithAsync doAsync;
    @Inject doItWithAsync doAsyncTimeout;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter writer = response.getWriter();
        writer.println("<html>");
        writer.println("<head><title>Hello World Servlet</title></head>");
        writer.println("<body>");
        writer.println("<h1>New Thread with Context Experiment</h1>");
        try {
            String ret1 = doAsync.doItAsync().get(10, TimeUnit.SECONDS);
            writer.println("<h2>Result1: "+ ret1+"</h2>");
            String ret2 = doAsyncTimeout.doItAsync().get(2, TimeUnit.SECONDS);
            writer.println("<h2>Result2: "+ ret2+"</h2>");
        } catch (TimeoutException e) {
            writer.println("<h2>Timeout Exception: "+ e.getMessage()+"</h2>");
            e.printStackTrace();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        writer.println("<body>");
        writer.println("</html>");
        writer.close();         
    }

    public static BeanManager getBeanManagerFromInitialContext() {
        try {
            InitialContext initialContext = new InitialContext();
            return (BeanManager) initialContext.lookup("java:comp/BeanManager");
        } catch (NamingException e) {
            logger.info("Couldn't get BeanManager through JNDI");
            return null;
        }
    }
}

タイムアウト チェックのために別のスレッドで実行する必要がある別の関数またはタスクは、@stateless セッション Bean として別のクラスに実装されます。

@Stateless
public class doItWithAsync {

    @Asynchronous
    public Future<String> doItAsync() throws Exception {
        Thread.sleep(5000);
        String result;
        if(HelloWorld.getBeanManagerFromInitialContext() == null) { 
            throw new Exception( "BEAN MANAGER IS NULL !"); 
        } else {
            result = "OK Async!!";
        }

        return new AsyncResult<String>(result);
    }
}

出力は次のようになります。

New Thread with Context
Result1: OK Async!!
Timeout Exception: JBAS014334: Task did not complete in 2 SECONDS
于 2014-08-30T19:37:59.820 に答える