web-dev-qa-db-ja.com

アプリケーションスコープのBeanがアプリケーションの起動時に強制的にインスタンス化されるようにするにはどうすればよいですか?

アプリケーションスコープのマネージドBeanを、Webアプリの起動時に強制的にインスタンス化/初期化する方法を見つけられないようです。アプリケーションスコープのBeanは、Webアプリの起動時ではなく、Beanに初めてアクセスしたときに遅延インスタンス化されるようです。私のWebアプリの場合、これは最初のユーザーが初めてWebアプリでページを開いたときに発生します。

これを避けたいのは、アプリケーションスコープのBeanの初期化中に、多くの時間のかかるデータベース操作が発生するためです。永続的なストレージから大量のデータを取得して、ListItem要素などの形式でユーザーに頻繁に表示されるデータの一部をキャッシュする必要があります。最初のユーザーが接続するときにすべてのことを実行したくないため、長い遅延を引き起こします。

私が最初に考えたのは、古いスタイルのServletContextListener contextInitialized()メソッドを使用し、そこからELResolverを使用して手動で管理対象Beanのインスタンスを要求することでした(したがって、初期化を強制します)。残念ながら、ELResolverはFacesContextを必要とし、FacesContextはリクエストの存続期間中にのみ存在するため、ELResolverを使用してこの段階で初期化をトリガーすることはできません。

誰かがこれを達成する別の方法を知っていますか?

MyFaces 1.2をJSF実装として使用していますが、現時点では2.xにアップグレードできません。

38
Jim Tough

私の最初の考えは、古いスタイルのServletContextListener contextInitialized()メソッドを使用し、そこからELResolverを使用してマネージドBeanのインスタンスを手動で要求することでした(したがって、初期化を強制します)。 ELResolverにはFacesContextが必要であり、FacesContextはリクエストの存続期間中にのみ存在するため、残念ながら、この段階ではELResolverを使用して初期化をトリガーすることはできません。

that複雑にする必要はありません。 Beanをインスタンス化し、same管理Bean名をキーとしてアプリケーションスコープに配置するだけです。 JSFは、スコープにすでに存在している場合、Beanを再利用します。 JSFがサーブレットAPIの上にある場合、ServletContextはアプリケーションスコープを表します(HttpSessionはセッションスコープを表し、HttpServletRequestはリクエストスコープを表し、それぞれsetAttribute()およびgetAttribute()メソッド)。

これで十分です

public void contextInitialized(ServletContextEvent event) {
    event.getServletContext().setAttribute("bean", new Bean());
}

ここで、"bean"は、<managed-bean-name>のアプリケーションスコープBeanのfaces-config.xmlと同じである必要があります。


参考までに、JSF 2.xでは、eager=true Beanの@ManagedBean@ApplicationScopedを追加するだけで済みます。

@ManagedBean(eager=true)
@ApplicationScoped
public class Bean {
    // ...
}

その後、アプリケーションの起動時に自動インスタンス化されます。

または、CDI @NamedでバッキングBeanを管理している場合は、 OmniFaces@Eager を取得します。

@Named
@Eager
@ApplicationScoped
public class Bean {
    // ...
}
58
BalusC

Romain Manni-Bucauさんは、CDI 1.1を使用するこの素晴らしいソリューションを blog に投稿しました。

トリックは、組み込みのライフサイクルスコープの初期化をBeanに観察させることです。つまり、この場合はApplicationScopedです。これは、シャットダウンのクリーンアップにも使用できます。したがって、例は次のようになります。

@ApplicationScoped
public class ApplicationScopedStartupInitializedBean {
    public void init( @Observes @Initialized( ApplicationScoped.class ) Object init ) {
        // perform some initialization logic
    }

    public void destroy( @Observes @Destroyed( ApplicationScoped.class ) Object init ) {
        // perform some shutdown logic
    }
}
16
Hein Blöd

私の知る限り、アプリケーションの起動時にマネージドBeanを強制的にインスタンス化することはできません。

マネージドBeanをインスタンス化する代わりに、それ自体ですべてのデータベース操作を実行するServletContextListenerを使用できますか?


別の解決策は、アプリケーションの起動時にBeanを手動でインスタンス化し、そのBeanをServletContextの属性として設定することです。

ここにコードサンプルがあります:

public class MyServletListener extends ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) {
        ServletContext ctx = sce.getServletContext();
        MyManagedBean myBean = new MyManagedBean();
        ctx.setAttribute("myManagedBean", myManagedBean);
    }

}

私の意見では、これはクリーンなコードからはほど遠いですが、それはトリックを行うようです。

2
Vivien Barousse