Pourquoi JSF appels getters plusieurs fois
Disons que je spécifier un outputText composant comme ceci:
<h:outputText value="#{ManagedBean.someProperty}"/>
Si j'ai l'impression d'un journal de message lors de la lecture pour someProperty
est appelé et charger la page, il est trivial de remarquer que le getter est appelé plus d'une fois par la demande (deux ou trois fois, c'est ce qui s'est passé dans mon cas):
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
Si la valeur de someProperty
est coûteux à calculer, cela peut éventuellement être un problème.
J'ai googlé un peu et pensé que c'est un problème connu. Une solution de contournement a été inclure un contrôle et voir si elle a déjà été calculé:
private String someProperty;
public String getSomeProperty() {
if (this.someProperty == null) {
this.someProperty = this.calculatePropertyValue();
}
return this.someProperty;
}
Le principal problème avec ceci est que vous obtenez des tonnes de code réutilisable, pour ne pas mentionner les variables privées que vous ne pourriez pas besoin.
Quelles sont les alternatives à cette approche? Il est un moyen d'atteindre cet objectif sans donc beaucoup de code inutile? Est-il un moyen d'arrêter de JSF de se comporter de cette façon?
Merci pour vos commentaires!
Vous devez vous connecter pour publier un commentaire.
Ceci est causé par la nature de différé expressions
#{}
(à noter que "l'héritage" expressions standard${}
se comportent exactement de la même quand Facelets est utilisé à la place de JSP). Le différé d'expression n'est pas immédiatement évaluée, mais les créé uneValueExpression
de l'objet et de la méthode de lecture derrière l'expression est exécutée chaque fois que le code appelleValueExpression#getValue()
.Ce sera généralement invoqué une ou deux fois par JSF cycle de requête-réponse, selon que le composant est une entrée ou une sortie composante (il apprend ici). Toutefois, ce nombre peut obtenir jusqu' (beaucoup) plus élevée lorsque utilisé dans l'itération composants JSF (comme
<h:dataTable>
et<ui:repeat>
), ou ici et là, dans une expression booléenne comme lerendered
attribut. JSF (plus précisément, EL) de ne pas mettre en cache le résultat évaluée de l'expression EL, vu qu'il peut retour des valeurs différentes à chaque appel (par exemple, lorsqu'elle est dépendante de l'itération en ligne de datatable).De l'évaluation d'une expression EL et l'invocation d'une méthode de lecture est un très bon marché de l'opération, de sorte que vous devez généralement vous inquiétez pas à ce sujet. Cependant, l'histoire des changements lorsque vous effectuez cher DB/logique métier dans la méthode de lecture pour une raison quelconque. Ce serait ré-exécuté à chaque fois!
Des méthodes de lecture en JSF sauvegarde des haricots doivent être conçus de manière qu'elles uniquement retour déjà préparé des biens et rien de plus, exactement comme par le Javabeans spécification. Ils ne devraient pas faire cher DB/d'affaires de la logique. Pour que le haricot
@PostConstruct
et/ou (action)auditeur méthodes doivent être utilisées. Ils sont exécutés qu'une seule fois à un certain moment de la demande de base de JSF le cycle de vie et c'est exactement ce que vous voulez.Voici un résumé de tous les différents droit moyens de préréglage/charger une propriété.
Notez que vous ne devez pas utiliser bean du constructeur ou de l'initialisation du bloc pour l'emploi, parce qu'il peut être invoqué plusieurs fois si vous utilisez un haricot cadre de gestion qui utilise des proxy, tels que les CDI.
Si il y a pour vous avez vraiment pas d'autres moyens, en raison d'une conception restrictive des exigences, alors vous devez introduire le chargement paresseux à l'intérieur de la méthode de lecture. I. e. si la propriété est
null
, puis le charger et de l'affecter à la propriété, de restitution.De cette façon, le cher DB/logique d'entreprise ne sera pas nécessairement être exécutée sur chaque unique de lecture d'appel.
Voir aussi:
@ViewScoped
au lieu de@RequestScoped
. Ou tout simplement régler le fonctionnement de la mémoire cache JPA niveau.value="#{myBean.someProperty}
", comme vous l'avez dit, ce qui appelle méthode d'accesseurgetSomeProperty()
plusieurs fois. Cependant, si nous faisons celavalue=#{myBean.someMethod()}
(GF EL nous permettent de le faire), et danssomeMethod()
jereturn someProperty;
, est ce que cette astuce JSF de ne pas invoquersomeMethod()
multiples fois ou nevalue expression EL
sais pour traitersomeMethod()
.List
dans dataTable, et pour chaqueitem
j'ai besoin d'interroger DB de base sur les valeurs de chaqueitem
. Plus l'utilisateur peut au moment de l'exécution en plus d'articles dans la dataTable.FacesContext#getCurrentPhaseId()
.Avec JSF 2.0, vous pouvez connecter un écouteur à un événement système
Sinon, vous pouvez joindre le JSF page dans un
f:view
tagJ'ai écrit une l'article sur la façon de cache JSF fèves de lecture avec Spring AOP.
J'ai créer un simple
MethodInterceptor
qui intercepte toutes les méthodes annotées avec une annotation:L'intercepteur est utilisé dans une configuration spring fichier:
Espère que ça va aider!
Posté dans PrimeFaces forum @ http://forum.primefaces.org/viewtopic.php?f=3&t=29546
Récemment, j'ai été obsédé par l'évaluation de la performance de mon application, tuning JPA requêtes, en remplacement de requêtes SQL avec des requêtes nommées, et ce matin, j'ai reconnu qu'une méthode de lecture a été plus d'un point CHAUD en Java, Visual VM que le reste de mon code (ou la majorité de mon code).
Méthode de lecture:
Référencé par l'interface utilisateur:inclure dans l'index.xhtml
Ci-dessous, vous verrez que PageNavigationController.getGmapsAutoComplete() est un point CHAUD (problème de performance) en Java, Visual VM. Si vous regardez plus loin, sur la capture d'écran, vous verrez que getLazyModel(), PrimeFaces paresseux datatable méthode de lecture, est un point chaud aussi, que lorsque l'utilisateur final est de faire beaucoup de "paresseux datatable" type de stuff/opérations/tâches dans l'application. 🙂
Voir (original) code ci-dessous.
Référencé par la suite dans l'index.xhtml:
Solution: puisque c'est un "getter" la méthode, passer le code et d'attribuer de la valeur à gmapsAutoComplete avant l'appel d'une méthode; voir code ci-dessous.
Résultats du Test: PageNavigationController.getGmapsAutoComplete() n'est plus un point CHAUD en Java, Visual VM (ne s'affiche même pas plus)
Partage de ce sujet, car de nombreux utilisateurs experts ont conseillé junior JSF développeurs pour ne PAS ajouter du code dans "getter" des méthodes. 🙂
Si vous utilisez CDI, vous pouvez utiliser des Producteurs de méthodes.
Il sera appelé plusieurs fois, mais le résultat du premier appel est mis en cache dans le champ d'application de la fève et est efficace pour les méthodes de lecture que sont l'informatique ou de l'initialisation des objets lourds!
Voir ici, pour plus d'info.
Vous pourriez probablement utiliser des AOP pour créer une sorte de Aspect qui en cache les résultats de notre getters pour une durée configurable. Cela vous empêcherait d'avoir à copier-coller le code réutilisable dans des dizaines d'accesseurs.
C'est ce que nous appelons une optimisation prématurée. Dans les rares cas où un profileur vous dit que le calcul d'une propriété est extraordinairement coûteux que de l'appeler trois fois plutôt qu'une fois a un impact significatif sur les performances, vous ajoutez de la mise en cache comme vous le décrivez. Mais à moins de faire quelque chose de vraiment stupide comme factorisation de nombres premiers ou l'accès à une databse dans un getter, votre code a probablement une douzaine de pire des inefficacités dans des endroits que vous n'avez jamais pensé.
Je voudrais aussi des conseils à l'aide d'un tel Cadre que Primefaces au lieu de stock JSF, ils traitent de questions avant de JSF équipe d'e. g dans primefaces vous pouvez définir partielle soumettre. Sinon BalusC a expliqué, c'est bien.
Il encore un gros problème dans le programme JSF. Fo exemple, si vous avez une méthode
isPermittedToBlaBla
pour les contrôles de sécurité et à votre avis, vous avezrendered="#{bean.isPermittedToBlaBla}
ensuite, la méthode sera appelée plusieurs fois.La vérification de la sécurité pourrait être compliqué.e.g . Requête LDAP etc. Donc, vous devez éviter que avec
et vous devez vous assurer dans un bean de session par cette demande.
Ich pense JSF doit mettre en œuvre ici quelques extensions pour éviter les appels multiples (e.g annotation
@Phase(RENDER_RESPONSE)
calle cette méthode qu'une seule fois aprèsRENDER_RESPONSE
de phase...)