Ini disebabkan oleh sifat ekspresi yang ditangguhkan #{}
(perhatikan bahwa ekspresi standar "lawas" ${}
berperilaku sama persis ketika Facelet digunakan sebagai ganti JSP). Ekspresi yang ditangguhkan tidak segera dievaluasi, tetapi dibuat sebagai ValueExpression
objek dan metode pengambil di belakang ekspresi dieksekusi setiap kali ketika kode panggilan ValueExpression#getValue()
.
Ini biasanya akan dipanggil satu atau dua kali per siklus permintaan-respons JSF, tergantung pada apakah komponen tersebut merupakan komponen input atau output ( pelajari di sini ). Namun, jumlah ini bisa naik (jauh) lebih tinggi ketika digunakan dalam iterasi komponen JSF (seperti <h:dataTable>
dan <ui:repeat>
), atau di sana-sini dalam ekspresi boolean seperti rendered
atribut. JSF (khususnya, EL) tidak akan menembolok hasil yang dievaluasi dari ekspresi EL sama sekali karena dapat mengembalikan nilai yang berbeda pada setiap panggilan (misalnya, ketika itu tergantung pada baris dataat yang saat ini diulangi).
Mengevaluasi ekspresi EL dan menggunakan metode pengambil adalah operasi yang sangat murah, jadi Anda biasanya tidak perlu khawatir sama sekali. Namun, cerita berubah ketika Anda melakukan logika DB / bisnis mahal dalam metode pengambil karena beberapa alasan. Ini akan dieksekusi kembali setiap kali!
Metode getter dalam JSF backing beans harus dirancang sedemikian rupa sehingga mereka semata-mata mengembalikan properti yang sudah disiapkan dan tidak lebih, sesuai dengan spesifikasi orang Jawa . Mereka seharusnya tidak melakukan logika bisnis / DB yang mahal sama sekali. Untuk itu @PostConstruct
metode pendengar kacang dan / atau (tindakan) harus digunakan. Mereka dieksekusi hanya sekali pada satu titik siklus hidup JSF berdasarkan permintaan dan itulah yang Anda inginkan.
Berikut adalah ringkasan dari semua berbeda hak cara untuk preset / memuat properti.
public class Bean {
private SomeObject someProperty;
@PostConstruct
public void init() {
// In @PostConstruct (will be invoked immediately after construction and dependency/property injection).
someProperty = loadSomeProperty();
}
public void onload() {
// Or in GET action method (e.g. <f:viewAction action>).
someProperty = loadSomeProperty();
}
public void preRender(ComponentSystemEvent event) {
// Or in some SystemEvent method (e.g. <f:event type="preRenderView">).
someProperty = loadSomeProperty();
}
public void change(ValueChangeEvent event) {
// Or in some FacesEvent method (e.g. <h:inputXxx valueChangeListener>).
someProperty = loadSomeProperty();
}
public void ajaxListener(AjaxBehaviorEvent event) {
// Or in some BehaviorEvent method (e.g. <f:ajax listener>).
someProperty = loadSomeProperty();
}
public void actionListener(ActionEvent event) {
// Or in some ActionEvent method (e.g. <h:commandXxx actionListener>).
someProperty = loadSomeProperty();
}
public String submit() {
// Or in POST action method (e.g. <h:commandXxx action>).
someProperty = loadSomeProperty();
return "outcome";
}
public SomeObject getSomeProperty() {
// Just keep getter untouched. It isn't intented to do business logic!
return someProperty;
}
}
Perhatikan bahwa Anda tidak boleh menggunakan konstruktor kacang atau blok inisialisasi untuk pekerjaan itu karena dapat dipanggil beberapa kali jika Anda menggunakan kerangka kerja manajemen kacang yang menggunakan proxy, seperti CDI.
Jika ada untuk Anda benar-benar tidak ada cara lain, karena beberapa persyaratan desain yang membatasi, maka Anda harus memperkenalkan pemuatan malas di dalam metode pengambil. Yaitu jika properti itu null
, lalu muat dan tetapkan ke properti, kalau tidak kembalikan.
public SomeObject getSomeProperty() {
// If there are really no other ways, introduce lazy loading.
if (someProperty == null) {
someProperty = loadSomeProperty();
}
return someProperty;
}
Dengan cara ini, DB / logika bisnis yang mahal tidak perlu dieksekusi pada setiap panggilan getter tunggal.
Lihat juga:
FacesContext#getCurrentPhaseId()
.Dengan JSF 2.0 Anda dapat melampirkan pendengar ke acara sistem
Atau Anda dapat melampirkan halaman JSF dalam
f:view
tagsumber
Saya telah menulis artikel tentang cara men-cache pembuat getah JSF dengan Spring AOP.
Saya membuat sederhana
MethodInterceptor
yang memotong semua metode yang dijelaskan dengan penjelasan khusus:Pencegat ini digunakan dalam file konfigurasi pegas:
Semoga ini bisa membantu!
sumber
Awalnya diposting di forum PrimeFaces @ http://forum.primefaces.org/viewtopic.php?f=3&t=29546
Baru-baru ini, saya terobsesi mengevaluasi kinerja aplikasi saya, menyetel kueri JPA, mengganti kueri SQL dinamis dengan kueri bernama, dan baru pagi ini, saya menyadari bahwa metode pengambil adalah lebih dari HOT SPOT di Java Visual VM daripada sisanya kode saya (atau sebagian besar kode saya).
Metode pengambil:
Dirujuk oleh ui: sertakan di dalam index.xhtml
Di bawah ini, Anda akan melihat bahwa PageNavigationController.getGmapsAutoComplete () adalah HOT SPOT (masalah kinerja) di Java Visual VM. Jika Anda melihat lebih jauh ke bawah, pada tangkapan layar, Anda akan melihat bahwa getLazyModel (), metode pengambil datatable malas PrimeFaces, juga merupakan hot spot, hanya ketika pengguna akhir melakukan banyak jenis barang / operasi / tugas 'malas datatable' dalam aplikasi. :)
Lihat kode (asli) di bawah ini.
Dirujuk oleh yang berikut di index.xhtml:
Solusi: karena ini adalah metode 'pengambil', pindahkan kode dan berikan nilai ke gmapsAutoComplete sebelum metode dipanggil; lihat kode di bawah ini.
Hasil pengujian: PageNavigationController.getGmapsAutoComplete () bukan lagi HOT SPOT di Java Visual VM (bahkan tidak muncul lagi)
Berbagi topik ini, karena banyak pengguna ahli telah menyarankan pengembang JSF junior untuk TIDAK menambahkan kode dalam metode 'pengambil'. :)
sumber
Jika Anda menggunakan CDI, Anda dapat menggunakan metode Produsen. Ini akan dipanggil berkali-kali, tetapi hasil dari panggilan pertama di-cache dalam lingkup bean dan efisien untuk getter yang menghitung atau menginisialisasi objek berat! Lihat di sini , untuk info lebih lanjut.
sumber
Anda mungkin dapat menggunakan AOP untuk membuat semacam Aspek yang menyimpan hasil getter kami untuk waktu yang dapat dikonfigurasi. Ini akan mencegah Anda dari perlu untuk menyalin dan menempelkan kode boilerplate di puluhan accessor.
sumber
Inilah yang kami sebut optimasi prematur. Dalam kasus yang jarang terjadi, seorang profiler memberi tahu Anda bahwa penghitungan properti sangat mahal sehingga menyebutnya tiga kali daripada sekali memiliki dampak kinerja yang signifikan, Anda menambahkan caching seperti yang Anda gambarkan. Tetapi kecuali jika Anda melakukan sesuatu yang benar-benar bodoh seperti memfaktorkan bilangan prima atau mengakses databse dalam pengambil, kode Anda kemungkinan besar memiliki selusin inefisiensi yang lebih buruk di tempat-tempat yang tidak pernah Anda pikirkan.
sumber
Saya juga akan menyarankan menggunakan Kerangka Kerja seperti Primefaces alih-alih JSF saham, mereka membahas masalah seperti itu sebelum tim JSF e. g di primefaces Anda dapat mengatur pengiriman parsial. Kalau tidak, BalusC telah menjelaskannya dengan baik.
sumber
Ini masih masalah besar di JSF. Misalnya, jika Anda memiliki metode
isPermittedToBlaBla
untuk pemeriksaan keamanan dan menurut Anda, Anda punyarendered="#{bean.isPermittedToBlaBla}
maka metode tersebut akan dipanggil beberapa kali.Pemeriksaan keamanan bisa rumit misalnya. Permintaan LDAP dll. Jadi Anda harus menghindari itu dengan
dan Anda harus memastikan dalam sesi sesi ini per permintaan.
Saya pikir JSF harus menerapkan beberapa ekstensi di sini untuk menghindari beberapa panggilan (mis., Anasiasi
@Phase(RENDER_RESPONSE)
calle metode ini hanya sekali setelahRENDER_RESPONSE
fase ...)sumber