40

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

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

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

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

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

4

4 に答える 4

58

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

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

これは、

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

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


記録として、JSF 2.x で行う必要があるのは、Beanに追加eager=trueすることだけです。@ManagedBean@ApplicationScoped

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

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

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

@Named
@Eager
@ApplicationScoped
public class Bean {
    // ...
}
于 2010-08-30T13:24:04.223 に答える
24

Romain Manni-Bucau は、彼のブログに CDI 1.1 を使用した、これに対する優れたソリューションを投稿しました。

秘訣は、組み込みのライフサイクル スコープの初期化を 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
    }
}
于 2015-09-11T09:34:10.360 に答える
2

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

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


もう 1 つの解決策は、アプリケーションの起動時に手動で 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);
    }

}

私の意見では、これはきれいなコードとはほど遠いですが、うまくいくようです。

于 2010-08-30T13:06:01.490 に答える
-1

上記のBalusCの回答に加えて@Startup@Singleton(CDI)を使用できます。

//@Named    // javax.inject.Named:       only needed for UI publishing
//@Eager    // org.omnifaces.cdi.Eager:  seems non-standard like taken @Startup below
@Startup    // javax.ejb.Startup:        like Eager, but more standard
@Singleton  // javax.ejb.Singleton:      maybe not needed if Startup is there
//@Singleton( name = "myBean" )  //      useful for providing it with a defined name
@ApplicationScoped
public class Bean {
    // ...
}

ここでうまく説明されています。少なくとも JPA 2.1 で動作します。

于 2016-01-19T08:30:02.787 に答える