2017-04-06 15 views
3

このコードが機能しない理由を理解できません。これはWildfly 10.1で実行されているCDI SessionScoped BeanへのアクセスがJava 8並列ストリームで機能しない

WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped 

:基本的に私はparallelStream()関数の中にCDI ViewScoped豆からCDI SessionScoped Beanにアクセスしたい、私はこの例外を取得します。

ViewScoped豆:

import java.io.Serializable; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.function.Function; 
import javax.faces.view.ViewScoped; 
import javax.inject.Inject; 
import javax.inject.Named; 

@ViewScoped 
@Named 
public class TestController implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Inject SessionController sessionController; 

    public void works() { 
     List<Function<String, String>> functions = new ArrayList<>(); 
     functions.add((String input) -> { 
      return sessionController.getSomething(); 
     }); 
     functions.add((String input) -> { 
      return sessionController.getSomethingElse(); 
     }); 
     functions.stream().forEach(f -> f.apply("input")); 
    } 

    public void doesNotWork() { 
     List<Function<String, String>> functions = new ArrayList<>(); 
     functions.add((String input) -> { 
      return sessionController.getSomething(); 
     }); 
     functions.add((String input) -> { 
      return sessionController.getSomethingElse(); 
     }); 
     functions.parallelStream().forEach(f -> f.apply("input")); 
    } 
} 

SessionScoped豆:

import java.io.Serializable; 
import javax.enterprise.context.SessionScoped; 
import javax.inject.Named; 

@Named 
@SessionScoped 
public class SessionController implements Serializable { 
    private static final long serialVersionUID = 1L; 

    public String getSomething() { 
     return "something"; 
    } 
    public String getSomethingElse() { 
     return "else"; 
    } 
} 

XHTML:

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:p="http://primefaces.org/ui"> 

    <h:head /> 

    <h:body> 
     <h:form> 
      <p:commandButton value="Works" action="#{testController.works}" /> 
      <br /> 
      <p:commandButton value="Does Not Work" action="#{testController.doesNotWork}" /> 
     </h:form> 
    </h:body> 
</html> 

スタックトレース:

Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped 
    at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689) 
    at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90) 
    at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165) 
    at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63) 
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83) 
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125) 
    at com.SessionController$Proxy$_$$_WeldClientProxy.getSomething(Unknown Source) 
    at com.TestController.lambda$3(TestController.java:33) 
    at com.TestController.lambda$5(TestController.java:38) 
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) 
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) 
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) 
    at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291) 
    at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731) 
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) 
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) 
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) 
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) 

私たちは、セッションは、特定のスレッドすることができる理論、ないハード証拠を持っています。

回避策がある場合はまた興味があります。実際のコードはこれよりはるかに複雑ですので、並列ストリームの利点を失うことなく、事前にSessionControllerの結果をプリロードすることはできません。

+0

パフォーマンス上の理由からparellelストリームが重要な現実的なケースはまだありません –

+0

この場合、各関数で異なるSQLクエリを実行しているため、完了するまでに最長のものを待つだけです私たちのSQL Serverに対して –

+2

パラレルストリームはIO操作で使用されることはありません。代わりに、非常に長いリストの要素をN個の部分に分割し、N個の部分リストの合計を並行して実行し、最終的に副題を合計するなど、並列計算を実行するために使用することを意図しています。 –

答えて

3

並列ストリームを使用するということは、複数のスレッドで実行されるということです。さて、これはCDIとコンテキストの問題です。メインスレッドでは、現在(例えば)セッションコンテキストがアクティブですが、別のスレッドを作成するとそこではアクティブではありません。

Chapter 6.3 in specは、他のスレッドへのコンテキストの伝達がデフォルトでは機能しません。です。また、非常にコストがかかり(同期)、スレッドの無効化セッションの1つを持つなどの非常に奇妙な状況を解決する必要があるため、他のスレッドが操作している間にセッションコンテキストを非アクティブ化する必要があります。そしてもっと多くのそのような状況。

また、組み込みの回避策もありません。あなたができることは、自分のスコープを実装すること、または既存のセッションスコープを強化することですが、それは私が推測すると非常に複雑になります。

+0

ありがとうございます、スコープがスレッドに非常に密接に結びついていることはわかりませんでした。この答えにあなたの時間と労力を感謝します。 –

1

Java EEでクエリを並列化する場合は、ManagedExecutorServiceを使用することをお勧めします。並列ストリームを使用するフォーク結合プールは、IOを計算するのではなく、並列処理を行うためのものです。

CDIコンテキストの伝播に関しては、CDI実装としてWELDを使用していると仮定すると、BoundSessionContextが便利です。続きを読むhttp://john-ament.blogspot.fi/2014/01/bridging-netty-resteasy-and-weld.html

おそらく、バインドされたセッションコンテキストなしで管理できます。セッションコンテキストから必要なデータをすべて集めてワーカースレッドに渡すだけです。

関連する問題