プログラムで(サーブレットinit()内から)ManagedBeanクラスをアプリケーションスコープに登録/追加したいと思います。JSF 1.2でそれを行うにはどうすればよいですか?
5 に答える
すべてのスコープのマネージドBeanのアプリケーションから、プログラムでこれを実行できる可能性はほとんどありません。BalusCは、アプリケーションスコープのマネージドBeanに対してこれを行う方法をすでに指摘しています。
管理対象BeanがMojarra2.1(JSF 2.1実装)にどのように登録されているかを確認しました。セッションのプログラムによる登録とスコープ付きBeanの要求に使用できるエレガントなオプションは多くありません。簡単に言うと、実装固有のクラスを呼び出すか、JSF実装に依存するのではなく、自分でBeanを作成および破棄する、つまり管理する必要があります。
リクエストスコープとセッションスコープにBeanを設定する(管理されていない方法)
注-これは、コンテナーではなくBeanを構築しているため、「管理されていない方法」と呼ばれます。アノテーションは、自分で処理して適切なメソッドを呼び出さない限り、機能@PostConstruct
し@PreDestroy
ません。依存性注入でさえ機能しません。
EL式は常に実行時に評価されるため、評価の前にスコープにBeanを設定する十分な機会が与えられます(機会があれば、足を撃ち抜くことができます)。Mojarra(および場合によっては他のJSF実装)では、ELリゾルバーはScopeHandler(または同等のクラス)のサービスに依存してEL式の値を解決します。MojarraはクラスApplicationScopeHandler
を使用し、さまざまなスコープから値を取得しますRequestScopeHandler
。SessionScopeHandler
新しいセッションが作成された後、またはリクエストがJSF実装によって処理される前に、セッションスコープとリクエストスコープのコンテンツを設定できます。
セッションスコープの作成は、以下を使用して(理想的にはを使用してHttpSessionListener
)実行できます。
HttpSession session = request.getSession(false);
session == null ? null : session.setAttribute("<keyname>", new Bean());
EL式でBeanを参照するために使用している値と一致するkeyname
必要があります。
同様の方法で、以下を使用してリクエストスコープにデータを入力できます(理想的にはフィルターで実行されます)。
ServletRequest request = ... // get the reference to the servlet request object
request.setAttribute("<keyname>", new Bean());
これがどのように機能するかを理解する必要がある場合は、クラスcom.sun.faces.context.SessionMap
を調べて、コンテキストマップが内部com.sun.faces.context.RequestMap
でcom.sun.faces.context.ApplicationMap
どのように管理され、によって使用されるかSessionScopeHandler
、RequestScopeHandler
および(別の静的内部)クラスのApplicationScopeHandler
静的内部クラスであるクラスを確認する必要があります。クラスScopeManager
。com.sun.faces.mgbean.BeanManager
このBeanManager
クラスは、マネージドBeanの登録を含むクラスであり、次のセクションでは、Mojarraの登録プロセスを「ハッキング」する方法について説明します。
Mojarraクラスを使用してBeanを登録する
Mojarra実装でのマネージドBeanの登録は、クラスのpublic void register(ManagedBeanInfo beanInfo)
メソッドによって行われます。JSFまたはサーブレットAPIのみを使用してクラスcom.sun.faces.mgbean.BeanManager
にアクセスすることは簡単ではありません。BeanManager
ただし、インスタンスApplicationAssociate
を作成するMojarraのクラスがあり、メソッドBeanManager
を使用してアクセスできます。getCurrentInstance()
Thomasによるもう1つの回答は、マネージドBeanをプログラムで登録する方法をすでに示しています。
ApplicationAssociate.getCurrentInstance().getBeanManager().register(...)
上記のアプローチには注意が必要です。メソッドがインスタンスを取得するためにThreadLocal変数に依存しているServlet
という単純な理由から、このアプローチがのinitメソッドで機能する可能性は低いです。スレッドローカル変数はクラスによって初期化されるため、インスタンスにアクセスするには、クラスが使用するメソッドを呼び出すメカニズムを再現する必要があります。したがって、次のコードは、Mojarra固有のクラスを使用する場合は、(私は使用を試みていませんが)より適切なコードである可能性があります。getCurrentInstance
ApplicationAssociate
com.sun.faces.application.WebappLifecycleListener
WebappLifecycleListener
ApplicationAssociate getInstance(ServletContext context)
ApplicationAssociate
ServletContext sc = ... //get the ServletContext reference;
ApplicationAssociate.getInstance(sc).getBeanManager().register(...)
一部のMojarraクラスおよびインスタンスがサーブレットの前にロードまたは初期化されていない可能性が高いため、このメカニズムから生じる癖に注意する必要があります。したがって、load-on-startup
によって使用される値よりも高い値でサーブレットを構成しようとしてロードすることをお勧めしますFacesServlet
。
サーブレット内から
init()
したがって、JSF以外の要求に関係します。ここにFacesContext#getCurrentInstance()
戻るnull
ので、ここでは役に立ちません。
JSFアプリケーションスコープのマネージドBeanは、基本的にの属性として格納されることを知っておくとよいでしょうServletContext
。このinit()
メソッドServletContext
では、継承されたメソッドを使用できますgetServletContext()
。したがって、次のようにする必要があります。
@Override
public void init() {
getServletContext().setAttribute("managedBeanName", new BackingBean());
}
それでおしまい。によってJSFで利用できるようになります#{managedBeanName}
。
試してみてくださいFacesContext.currentInstance().getExternalContext().getApplicationMap().put(name, bean);
。つまり、式で使用する名前を使用して、マネージドBeanインスタンスをマップに配置します。
編集:
Beanを登録するには、次の呼び出しを試してください。入力ApplicationAssociate.getCurrentInstance().getBeanManager().register(...)
したaを渡しManagedBeanInfo
ます。
次のコードは、を使用してマネージドBeanを正しく登録しFacesContext
ますが、サーブレットの要求と応答が必要です。コードを使用して、初期化中ではなくサーブレットを使用して遅延的に初期化することができます。
使用法:
UserBean ub = (UserBean)
Example.getBean(servletRequest, servletResponse, "user", UserBean.class);
ソース:
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class Example {
public static Object getBean(HttpServletRequest request, HttpServletResponse response, String beanName, Class expectedType){
FacesContext ctx = getFacesContext(request, response);
ValueExpression vex = ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(), "#{"+beanName+"}", expectedType);
return vex.getValue(ctx.getELContext());
}
private static FacesContext getFacesContext(HttpServletRequest request, HttpServletResponse response) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null) {
facesContext = ((FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY)).
getFacesContext(request.getSession().getServletContext(), request, response,
((LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY))
.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE));
InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);
facesContext.setViewRoot(facesContext.getApplication().getViewHandler().createView(facesContext, ""));
}
return facesContext;
}
private abstract static class InnerFacesContext extends FacesContext {
protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) {
FacesContext.setCurrentInstance(facesContext);
}
}
}
を使用してBeanを登録したとします
ApplicationAssociate.getInstance(sc).getBeanManager().register(...)
これで正常に動作していますが、サーバーが再起動し、Beanが破棄されます。起動時に、同じBeanを登録するにはどうすればよいですか。