Kacang Jawa Stateless dan BUMN

94

Saya akan melalui tutorial Java EE 6 dan saya mencoba memahami perbedaan antara kacang sesi stateless dan stateful. Jika kacang sesi stateless tidak mempertahankan statusnya di antara pemanggilan metode, mengapa program saya bertindak seperti itu?

package mybeans;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

@LocalBean
@Stateless
public class MyBean {

    private int number = 0;

    public int getNumber() {
        return number;
    }

    public void increment() {
        this.number++;
    }
}

Klien

import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import mybeans.MyBean;
import java.io.PrintWriter;

@WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
public class ServletClient extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @EJB
    MyBean mybean;

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        PrintWriter out = response.getWriter();
        mybean.increment();
        out.println(mybean.getNumber());
    }

}

Saya mengharapkan getNumber untuk mengembalikan 0 setiap kali tetapi mengembalikan 1 dan memuat ulang servlet di browser saya meningkatkannya lebih banyak. Masalahnya adalah dengan pemahaman saya tentang bagaimana kacang sesi stateless bekerja dan bukan dengan perpustakaan atau server aplikasi, tentu saja. Dapatkah seseorang memberi saya contoh tipe hello world sederhana dari kacang sesi stateless yang berperilaku berbeda ketika Anda mengubahnya menjadi stateful?

Stanley kelly
sumber
6
Terkait: stackoverflow.com/questions/8887140/… Jawaban ini mungkin lebih sederhana untuk dipahami. Perhatikan bahwa servlet pada dasarnya adalah cakupan aplikasi (hanya ada 1 instance servlet di seluruh aplikasi yang dibagikan / digunakan kembali di semua permintaan / sesi HTTP.
BalusC
hai, Anda melakukan kenaikan pertama, dan kemudian mendapatkan nilainya .... jadi Anda tidak dapat mengharapkan nilai 0.
rzur2004
Saya hanya ingin berterima kasih karena menanyakan hal ini, ini menjawab masalah saya saat ini. Saya tidak bisa meminta yang lebih baik
kholofelo Maloma

Jawaban:

94

Perbedaan penting bukanlah variabel anggota pribadi, tetapi status pengaitan dengan pengguna tertentu (pikirkan "keranjang belanja").

Potongan stateful session bean seperti sesi di servlet. Kacang sesi yang stateful memungkinkan aplikasi Anda untuk tetap memiliki sesi tersebut meskipun tidak ada klien web. Saat server aplikasi mengambil kacang sesi stateless dari kumpulan objek, ia tahu bahwa itu bisa digunakan untuk memenuhi permintaan APA PUN, karena tidak terkait dengan pengguna tertentu.

Kacang sesi stateful harus dibagikan kepada pengguna yang mendapatkannya di tempat pertama, karena info keranjang belanja mereka harus diketahui hanya oleh mereka. Server aplikasi memastikan demikian. Bayangkan betapa populernya aplikasi Anda jika Anda dapat mulai berbelanja dan kemudian server aplikasi memberikan kacang sesi stateful Anda kepada saya ketika saya datang!

Jadi anggota data pribadi Anda memang "negara bagian", tetapi bukan "keranjang belanja". Coba ulangi contoh Anda (sangat bagus) untuk membuatnya sehingga variabel yang ditambahkan dikaitkan dengan pengguna tertentu. Tingkatkan, buat pengguna baru, dan lihat apakah mereka masih dapat melihat nilai yang ditambahkan. Jika dilakukan dengan benar, setiap pengguna hanya akan melihat versi penghitung mereka.

duffymo
sumber
Dapatkah Anda memberikan jawaban eksplisit dalam komentar? Mengapa selalu kacang tanpa kewarganegaraan dalam contoh ini memiliki nilai dan meningkatkannya setiap saat? Karena hanya ada satu pengguna?
arjacsoh
2
Penghitung akan bertambah terlepas dari jumlah pengguna. Jadi jika pengguna1 masuk dan menambah penghitung menjadi 1 dan secara bersamaan pengguna2 masuk dan menambahkannya, nilainya akan menjadi 2. Ini sebenarnya harus menunjukkan bahwa pengguna1 memiliki 1 dan pengguna2 memiliki 1 (jika itu yang ingin Anda lakukan. contoh seperti di atas).
Krishna
138

Stateless Session Beans (SLSB) tidak terikat pada satu klien dan tidak ada jaminan bagi satu klien untuk mendapatkan instans yang sama dengan setiap pemanggilan metode (beberapa kontainer dapat membuat dan menghancurkan kacang dengan setiap sesi pemanggilan metode, ini adalah keputusan khusus implementasi , tetapi contoh biasanya dikumpulkan - dan saya tidak menyebutkan lingkungan berkerumun). Dengan kata lain, meskipun kacang stateless mungkin memiliki variabel instance, kolom ini tidak spesifik untuk satu klien, jadi jangan mengandalkannya di antara panggilan jarak jauh.

Sebaliknya, Stateful Session Beans (SFSB) didedikasikan untuk satu klien seumur hidup mereka, tidak ada pertukaran atau penggabungan contoh (mungkin dikeluarkan dari memori setelah pasif untuk menghemat sumber daya tetapi itu cerita lain) dan mempertahankan status percakapan . Ini berarti bahwa variabel instan kacang dapat menyimpan data relatif terhadap klien di antara pemanggilan metode. Dan ini memungkinkan untuk memiliki panggilan metode yang saling bergantung (perubahan yang dibuat oleh satu metode memengaruhi panggilan metode selanjutnya). Proses multi-langkah (proses pendaftaran, keranjang belanja, proses pemesanan ...) adalah kasus penggunaan khas untuk SFSB.

Satu hal lagi. Jika Anda menggunakan SFSB, Anda harus menghindari menyuntikkannya ke dalam kelas yang bersifat multithread, seperti Servlets dan kacang yang dikelola JSF (Anda tidak ingin itu dibagikan oleh semua klien). Jika Anda ingin menggunakan SFSB dalam aplikasi web Anda, maka Anda perlu melakukan pencarian JNDI dan menyimpan instance EJB yang dikembalikan dalam HttpSessionobjek untuk aktivitas di masa mendatang. Sesuatu seperti itu:

try {
    InitialContext ctx = new InitialContext();
    myStateful = (MyStateful)ctx.lookup("java:comp/env/MyStatefulBean");
    session.setAttribute("my_stateful", myStateful);
} catch (Exception e) {
    // exception handling
}
Pascal Thivent
sumber
Terima kasih atas penjelasannya. Ketika saya menggunakan program baris perintah mandiri untuk klien, jelas terlihat perbedaannya.
Stanley kelly
terima kasih atas komentar Anda, mereka lebih mencerahkan. pertama Anda memberikan definisi abstrak, kemudian menentukan beberapa kasus penggunaan untuk setiap situasi, dan kemudian menunjukkan beberapa kendala. +1 Hebat
arthur
Apakah bagian menghindari injeksi juga keluar untuk EJB 3.1?
jacktrades
7
@Pascal jika "Stateful Session Beans (SFSB) didedikasikan untuk satu klien seumur hidup mereka", maka kemampuan ini dibangun di SFSB, lalu mengapa perlu menyimpannya di objek HttpSession?
pengguna1169587
2
Mengapa kita perlu mengadakan stateful bean dalam sesi jika sudah 'sessioned'? Dengan cara ini kita dapat membuat setiap objek menjadi sesi.
Tolong
18

Stateless dan stateful dalam konteks ini tidak berarti seperti yang Anda harapkan.

Statefulness dengan EJB mengacu pada apa yang saya sebut keadaan percakapan . Contoh klasiknya adalah pemesanan penerbangan. Jika terdiri dari tiga langkah:

  • Pesan kursi
  • Tagih kartu kredit
  • Terbitkan Tiket

Bayangkan masing-masing adalah panggilan metode ke kacang sesi. Kacang sesi yang stateful dapat mempertahankan jenis percakapan ini sehingga dapat mengingat apa yang terjadi di antara panggilan.

Kacang sesi tanpa negara tidak memiliki kapasitas seperti itu untuk keadaan percakapan.

Variabel global di dalam kacang sesi (stateless atau stateful) adalah sesuatu yang sama sekali berbeda. Kacang sesi stateful akan memiliki kumpulan kacang yang dibuat (karena kacang hanya dapat digunakan dalam satu percakapan pada satu waktu) sedangkan kacang sesion stateless seringkali hanya memiliki satu contoh, yang akan membuat variabel global berfungsi, tetapi saya tidak berpikir ini tentu dijamin.

cletus
sumber
5

Pertanyaan bagus,

coba kode ini (ubah MyBean Stateful / Stateless.):

import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.ejb.Stateless;

@LocalBean 
@Stateless 
public class MyBean {

    private int number = 0;

    public int getNumber() {
        return number;
    }

    public void increment() {
        this.number++;
    }
}

Servlet_1

 import java.io.IOException;
    import javax.ejb.EJB;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import javax.servlet.annotation.WebServlet;

    import java.io.PrintWriter;

    @WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
    public class ServletClient extends HttpServlet {

        private static final long serialVersionUID = 1L;

        @EJB
        MyBean mybean;

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            PrintWriter out = response.getWriter();
            mybean.increment();
            out.println(mybean.getNumber());
        }

    }

Servlet_2

import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;

import java.io.PrintWriter;

@WebServlet(name = "NewServletClient", urlPatterns = { "/NewServletClient" })
public class NewServletClient extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @EJB
    MyBean mybean;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        PrintWriter out = response.getWriter();
        mybean.increment();
        out.println(mybean.getNumber());
    }

}

kasus: MyBean - @ Stateless

http: // localhost: 8080 / MYServletDemo / ServletClient

1

http: // localhost: 8080 / MYServletDemo / ServletClient

2

http: // localhost: 8080 / MYServletDemo_war_exploded / newServletClient

3

http: // localhost: 8080 / MYServletDemo / ServletClient

4

kasus: MyBean - @ Stateful

http: // localhost: 8080 / MYServletDemo / ServletClient

1

http: // localhost: 8080 / MYServletDemo / ServletClient

2

http: // localhost: 8080 / MYServletDemo / newServletClient

1

http: // localhost: 8080 / MYServletDemo / ServletClient

3

ZURA Tikaradze
sumber
1
Ya, itu dan Berhasil! Penjelasannya sangat mudah, terima kasih!
Nesquik27
5

Utama perbedaan antara dua jenis utama dari kacang sesi adalah:

Kacang Tanpa Negara

  1. Stateless Session Beans adalah kacang yang tidak memiliki status percakapan dengan klien yang disebut metodenya. Untuk alasan ini mereka dapat membuat kumpulan objek yang dapat digunakan untuk berinteraksi dengan banyak klien.
  2. Kacang stateless yang bijaksana kinerja lebih baik karena tidak memiliki status per klien.
  3. Mereka dapat menangani banyak permintaan dari banyak klien secara paralel.

Kacang Stateful

  1. Kacang sesi yang stateful dapat mempertahankan status percakapan dengan beberapa klien sekaligus dan tugas tidak dibagi di antara klien.
  2. Setelah sesi selesai, status tidak dipertahankan.
  3. Penampung dapat membuat serial dan menyimpan status sebagai status usang untuk digunakan di masa mendatang. Ini dilakukan untuk menghemat sumber daya server aplikasi dan untuk mendukung kegagalan kacang.
Pritam Banerjee
sumber
4

Hal ini terjadi karena container hanya memiliki satu instance bean di pool yang digunakan kembali untuk semua panggilan. Jika Anda menjalankan klien secara paralel, Anda akan melihat hasil yang berbeda karena wadah akan membuat lebih banyak instance kacang di kumpulan.

Neyma
sumber
4

Jawabannya bagus. Saya ingin menambahkan jawaban kecil. Stateless Bean tidak boleh digunakan untuk menyimpan data klien apa pun. Ini harus digunakan untuk "memodelkan tindakan atau proses yang dapat dilakukan dalam satu kesempatan".

Malatesh
sumber