0

ソケットに書き込むときに、この奇妙な問題が発生しています。アプリケーションは、Tomcat 5.5 で実行される Web アプリケーションです。問題の機能は、サーブレットからリクエストを受け取り、何らかの処理を行い、そのリクエストを SSLSocket 経由で外部システムに送信することです。

これは私の MessageProcessor クラスです:

public class MessageProcessor {

    private final int socketTimeout;
    private final int threadTimeout;

    private final ExecutorService executor = Executors.newCachedThreadPool();

    private static class Holder {
        static MessageProcessor instance = new MessageProcessor();
    }

    public static MessageProcessor instance() {
        return Holder.instance;
    }
    static {
        instance();
    }

    private MessageProcessor() {
        socketTimeout = /*get from property*/
                threadTimeout = /*get from property*/

                    //Setting Java SSL details
                    System.setProperty("javax.net.ssl.trustStore") /*from property*/;
        System.setProperty("javax.net.ssl.trustStorePassword") /*from property*/;

        socketFactory = SSLSocketFactory.getDefault();
    }

    public String submit(String msg) {
        Worker worker = new Worker(msg);
        try {
            return executor.submit(worker).get(threadTimeout,
                                               TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrade();
        }
        return "";
    }

    public String submitDirect(String msg) throws Exception {
        Worker worker = new Worker(msg);
        return worker.call();
    }

    class Worker implements Callable<String> {
        private String message;

        public Worker(String requestMsg) {
            this.message = requestMsg;
        }

        public String call() throws Exception {

            socket = socketFactory.createSocket();


            StringBuilder responseSb = new StringBuilder();
            StringBuilder frameMarkerSb = new StringBuilder();
            BufferedWriter socketWriter = null;
            BufferedReader socketReader = null;

            try {

                socketWriter =
                        new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                socketWriter.write(message);
                socketWriter.flush();

                socketReader =
                        new BufferedReader(new InputStreamReader(socket.getInputStream(),
                                                                 "UTF-8"));
                /* do something else */
                /* receive response */

            } catch (InterruptedIOException e) {
                //Error handling
            } catch (Exception e) {
                //Error handling
            } finally {
                socketWriter.close();
                socketReader.close();
                socket.close();
            }
            return response;
        }
    }
}

この方法で、サーブレットのこの MessageProcessor にメッセージを送信します。

protected void doPost(HttpServletRequest req,
                      HttpServletResponse resp) throws ServletException,
                                                       IOException {

    String requestStr = req.getParameter("data");
    String responseStr = "";

    try {
        responseStr =
                MessageProcessor.instance().submit(requestStr.trim());
        responseStr =
                MessageProcessor.instance().submitDirect(requestStr.trim());
    } catch (Exception e) {
        //Error handling
    }
    resp.setContentType("text/HTML");

    resp.getWriter().write(responseStr);
}

問題は submit() にあります。submit() では、タスクがキャッシュされたスレッド プールに送信され、この例外がスローされます。例外は socketWriter.flush() でスローされます。

  2012-09-06 13:17:36,007 [http-8080-1] ERROR processor.MessageProcessor - Error submitting new task
    java.util.concurrent.ExecutionException: java.lang.NullPointerException
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:232)
    at java.util.concurrent.FutureTask.get(FutureTask.java:91)
    at com.scb.race.bridge.processor.MessageProcessor.submit(MessageProcessor.java:70)
    at com.scb.race.bridge.servlet.CheckServlet.doPost(CreditCheckServlet.java:31)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:843)
    at   org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:679)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1303)
    at java.lang.Thread.run(Thread.java:619)
    Caused by: java.lang.NullPointerException
    at com.scb.race.bridge.processor.MessageProcessor$MessageWorker.call(MessageProcessor.java:140)
    at com.scb.race.bridge.processor.MessageProcessor$MessageWorker.call(MessageProcessor.java:78)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

submitDirect() を使用すると、call() メソッドはスレッド プールにサブミットせずに直接呼び出され、正常に動作します。

JUnit でクラスをテストしても問題はありません。Tomcat でのみ発生します。

誰かがこれに光を当てることができれば、本当に感謝しています。ここにたくさんのコードを入れてすみません。それは私を夢中にさせています。

4

2 に答える 2

0

この行から来たように見える問題の原因を見つけたと思います:

socketFactory = SSLSocketFactory.getDefault();

SocketFactory をスレッド ローカル変数に入れると、正常に動作します。

socketFactory = new ThreadLocal<SocketFactory>(){;
    protected SocketFactory initialValue() {
        return SSLSocketFactory.getDefault();
    }
};

したがって、SSLSocketFactory はスレッドセーフではないというのが私の結論です。ただし、これを裏付ける公式ドキュメントは見つかりませんでした。

于 2012-09-13T04:08:43.587 に答える
0
public String submitDirect(String pdcRequestStr) throws Exception {
    Worker worker = new Worker(msg);
    return worker.call();
}

new Worker(msg) を new Worker(pdcRequestStr) に変更

于 2012-09-06T09:01:26.557 に答える