2017-11-17 8 views
0

私は、Transformerインスタンスを読み込むシングルトンBeanを持つプラットフォームを用意しています(xsltはすべてのリクエストでインスタンスを作成するほど大きいので)。高並列環境でJavax Transformerが失敗する

通常のロードではすべてうまく動作しますが、膨大な数の同時リクエストでストレステストを行うと、トランスフォーマーはArrayIndexOutOfBoundsExceptionをスローして動作を停止し、サーバーインスタンスを再起動するかアプリケーションを再デプロイする必要があります。

これは、アプリケーションがデプロイされたとき、私は私のインスタンスを作成する方法です。

private Transformer createCFDI33TransformerInstance() { 

      InputStream in = new URL("http://www.sat.gob.mx/sitio_internet/cfd/3/cadenaoriginal_3_3/cadenaoriginal_3_3.xslt").openStream(); 

      TransformerFactory factory = TransformerFactory.newInstance();    
      Transformer transformer 
        = factory.newTransformer(new StreamSource(in)); 
      Logger.getLogger(PadeSingleton.class.getName()).log(Level.INFO, " Se ha cargado la instancia de XSLT"); 
      return transformer; 
     } catch (TransformerConfigurationException | IOException ex) { 
// Loading a remote instance was not possible so I will load a local instance 
      Logger.getLogger(PadeSingleton.class.getName()).log(Level.SEVERE, "No fue posible cargar una nueva instancia de cadena original, se usara la del sistema", ex); 
      InputStream in = CFDIv33Tools.class.getClassLoader() 
        .getResourceAsStream("com/soft/cadenaoriginal_3_3.xslt"); 

      TransformerFactory factory = TransformerFactory.newInstance(); 
      Transformer transformer; 
      try { 
       transformer = factory.newTransformer(new StreamSource(in)); 
       Logger.getLogger(PadeSingleton.class.getName()).log(Level.WARNING, "No fue posible cargar la instancia, se cargara una local"); 
      } catch (TransformerConfigurationException ex1) { 
       Logger.getLogger(PadeSingleton.class.getName()).log(Level.SEVERE, null, ex1); 
       // Estamos en problemas 
       throw new Exception("Error critico"); 
      } 
      return transformer; 
     } 
    } 

だから、他のBeanに私はシングルトンビーンを注入し、私の変圧器のインスタンスを取得するメソッドを呼び出します。この方法では

public static String transform(String xml, Transformer instance) throws Exception { 

     StringWriter writer = new StringWriter(); 

     try { 

      instance.transform(new StreamSource(new StringReader(xml)), new StreamResult(writer)); 

     } catch (TransformerException e) { 
      throw new Exception("El comprobante contiene simbolos no permitidos o esta mal formado", e); 
     } 

     return writer.toString(); 
    } 

私はこの例外がthrowedされたときに、次の要求は、この同じ例外で失敗し、私はストレステストを行うときにこの問題が発生した繰り返しは、ArrayIndexOutOfBoundsException

Caused by: javax.xml.transform.TransformerException: java.lang.ArrayIndexOutOfBoundsException: -1 
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:746) 
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:351) 
    at com.icontech.pade.common.xml.tools.CFDIv33Tools.calcularCadenaOriginalV2(CFDIv33Tools.java:93) 
    ... 138 more 

を取得する場所です。インスタンスが破損していると思われます。

+0

これはどのJavaバージョンが正確ですか?あなたは 'TransformerImpl.java'の746行で何が起きているのかを調べるためにJavaバージョンのソースを見つけようとしましたか?あなたは別のJavaバージョンを試しましたか?あなたはSaxon 9のような別のXSLT実装を試しましたか? –

+0

https://bugs.openjdk.java.net/browse/JDK-8062518も同じように聞こえますが、修正されているようですので、おそらくJavaバージョンを更新する必要があります。 –

+0

こんにちは!私はoracle JDK 1.8.0_151を使用しています – rafuru

答えて

1

Transformerはスレッドセーフではありません。コンパイルされたスタイルシートを表す単一のTemplatesオブジェクトを作成し、各変換に対して新しいTransformerオブジェクトをインスタンス化する必要があります。

(原則として、Transformerはシリアルで再利用可能ですので、変換が完了したら同じスレッド内でトランスフォーマーを再利用することができます)Xalanでこれを行うことでメリットがあるかどうかはわかりません;毎回新しいTransformerを作成する方が良いです。)

関連する問題