Comment forcer une application-scoped bean à instancier au démarrage de l'application?
Je ne peux pas trouver un moyen de forcer une application-scoped bean géré à être instancié/initialisé lorsque l'application web est lancé. Il semble que l'application-scoped haricots obtenir paresseux instantiated la première fois que le haricot est accédé, pas lorsque l'application web est lancé. Pour mon application web ce qui se passe lorsque le premier utilisateur ouvre une page dans l'application web pour la première fois.
la raison pour laquelle je veux éviter cela est parce qu'un certain nombre d'opérations de base de données fastidieuses se produire lors de l'initialisation de ma portée application de haricot. Il doit récupérer un tas de données du stockage persistant, puis mettre en cache une partie de celui-ci qui sera fréquemment affiché à l'utilisateur sous la forme D'éléments de ListItem, etc. Je ne veux pas que tout cela se produise lorsque le premier utilisateur se connecte et donc causer un long délai.
ma première pensée a été d'utiliser une ancienne méthode ServletContextListener contextInitialized() et à partir de là, utiliser un ELResolver pour demander manuellement l'instance de My managed bean (forçant ainsi l'initialisation à se produire). Malheureusement, je ne peux pas utiliser un ELResolver pour déclencher l'initialisation à ce stade parce que L'ELResolver a besoin d'un Facescontexte et que le Facescontexte n'existe que pendant la durée de vie d'une requête.
est-ce que quelqu'un connaît une autre façon d'accomplir ceci?
J'utilise MyFaces 1.2 comme implémentation JSF et je ne peux pas passer à 2.x en ce moment.
4 réponses
ma première pensée a été d'utiliser une ancienne méthode ServletContextListener contextInitialized() et d'utiliser à partir de là un ELResolver pour demander manuellement l'instance de mon bean managé (forçant ainsi l'initialisation à se produire). Malheureusement, je ne peux pas utiliser un ELResolver pour déclencher l'initialisation à ce stade parce que L'ELResolver a besoin d'un Facescontexte et que le Facescontexte n'existe que pendant la durée de vie d'une requête.
il n'est pas nécessaire que ce soit que soit compliqué. Instanciez simplement le haricot et mettez-le dans le champ d'application avec le même nom de haricot géré comme clé. JSF va juste réutiliser le haricot quand déjà présent dans le champ d'application. Avec JSF en plus de L'API Servlet, le ServletContext
représente le champ d'application (comme HttpSession
représente le champ d'application de la session et HttpServletRequest
représente le champ d'application de la requête, chacune avec les méthodes setAttribute()
et getAttribute()
).
il doit faire,
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("bean", new Bean());
}
où "bean"
doit être le même que <managed-bean-name>
de l'application scoped bean dans faces-config.xml
.
Juste pour le record, sur JSF 2.x Tout ce que vous devez faire est d'ajouter eager=true
à @ManagedBean
sur un haricot @ApplicationScoped
.
@ManagedBean(eager=true)
@ApplicationScoped
public class Bean {
// ...
}
Il sera alors instancié automatiquement au démarrage de l'application.
ou , lorsque vous gérez des haricots de soutien par CDI @Named
, puis saisir OmniFaces @Eager
:
@Named
@Eager
@ApplicationScoped
public class Bean {
// ...
}
Romain Manni-Bucau a publié une solution soignée à ce qui utilise CDI 1.1 sur son blog .
le truc est de laisser le haricot observer l'initialisation des portées de cycle de vie intégrées, i.e. ApplicationScoped
dans ce cas. Cela peut également être utilisé pour l'arrêt de nettoyage. Ainsi un exemple ressemble à ceci:
@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
}
}
autant que je sache, vous ne pouvez pas forcer un bean managé à être instancié au démarrage de l'application.
peut-être pourriez-vous utiliser un ServletContextListener qui, au lieu d'instancier votre bean managé, effectuera toutes les opérations de la base de données elle-même?
" une autre solution pourrait être d'instancier votre fève manuellement au démarrage de l'application, puis de définir la fève comme un attribut de votre ServletContext.
voici un exemple de code:
public class MyServletListener extends ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
MyManagedBean myBean = new MyManagedBean();
ctx.setAttribute("myManagedBean", myManagedBean);
}
}
à mon avis, c'est loin d'être du code propre, mais on dirait que ça fait l'affaire.
en plus de réponse de BalusC ci-dessus vous pouvez utiliser @Startup
et @Singleton
(CDI), par exemple
//@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 {
// ...
}
qui est bien expliqué ici . Il travaille au moins dans le JPA 2.1.