Đậu Java không trạng thái và doanh nghiệp có trạng thái


93

Tôi đang xem qua hướng dẫn Java EE 6 và tôi đang cố gắng hiểu sự khác biệt giữa phiên không trạng thái và phiên trạng thái. Nếu các bean phiên không trạng thái không giữ lại trạng thái của chúng giữa các lần gọi phương thức, tại sao chương trình của tôi lại hoạt động theo cách đó?

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++;
    }
}

Khách hàng

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());
    }

}

Tôi đã mong đợi getNumber trả về 0 mọi lúc nhưng nó đang trả về 1 và số lần tải lại servlet trong trình duyệt của tôi sẽ làm tăng nó nhiều hơn. Vấn đề là với sự hiểu biết của tôi về cách các phiên không trạng thái hoạt động và tất nhiên là không với các thư viện hoặc máy chủ ứng dụng. Ai đó có thể cho tôi một ví dụ đơn giản về kiểu hello world về bean phiên không trạng thái hoạt động khác khi bạn thay đổi nó thành trạng thái không?


6
Liên quan: stackoverflow.com/questions/8887140/… Câu trả lời này có thể đơn giản hơn để hiểu. Lưu ý rằng các servlet về cơ bản là phạm vi ứng dụng (chỉ có 1 ứng dụng phiên bản servlet được chia sẻ / sử dụng lại trên tất cả các yêu cầu / phiên HTTP.
BalusC 14/12/12

xin chào, Bạn thực hiện tăng đầu tiên, và sau đó nhận được giá trị .... vì vậy Bạn không thể mong đợi giá trị là 0.
rzur2004

Tôi chỉ muốn cảm ơn bạn đã hỏi điều này, nó giải quyết vấn đề của tôi vào lúc này. Tôi không thể đòi hỏi rằng tốt hơn
kholofelo Maloma

Câu trả lời:


93

Sự khác biệt quan trọng không phải là các biến thành viên riêng tư, mà là trạng thái liên kết với một người dùng cụ thể (nghĩ là "giỏ hàng").

Đoạn trạng thái của bean phiên trạng thái giống như phiên trong các servlet. Các bean phiên trạng thái cho phép ứng dụng của bạn vẫn có phiên đó ngay cả khi không có ứng dụng khách web. Khi máy chủ ứng dụng tìm nạp một bean phiên không trạng thái ra khỏi nhóm đối tượng, nó biết rằng nó có thể được sử dụng để đáp ứng BẤT KỲ yêu cầu nào vì nó không được liên kết với một người dùng cụ thể.

Một bean phiên trạng thái phải được cung cấp cho người dùng đã có nó ngay từ đầu, bởi vì thông tin giỏ hàng của họ chỉ được biết đến. Máy chủ ứng dụng đảm bảo rằng điều này là như vậy. Hãy tưởng tượng ứng dụng của bạn sẽ trở nên phổ biến như thế nào nếu bạn có thể bắt đầu mua sắm và sau đó máy chủ ứng dụng đã cung cấp hạt đậu phiên trạng thái của bạn cho tôi khi tôi đến cùng!

Vì vậy, thành viên dữ liệu cá nhân của bạn thực sự là "nhà nước", nhưng nó không phải là "giỏ hàng". Cố gắng làm lại ví dụ (rất tốt) của bạn để biến nó thành biến tăng dần được liên kết với một người dùng cụ thể. Tăng giá trị, tạo người dùng mới và xem liệu họ có còn thấy giá trị đã tăng hay không. Nếu thực hiện đúng, mọi người dùng sẽ chỉ thấy phiên bản bộ đếm của họ.


Bạn có thể cung cấp trong một bình luận một câu trả lời rõ ràng không? Tại sao bean không trạng thái trong ví dụ này luôn giữ giá trị và tăng nó mỗi lần? Vì chỉ có một người dùng?
arjacsoh

2
Bộ đếm sẽ tăng lên bất kể số lượng người dùng. Vì vậy, nếu user1 đến và tăng bộ đếm lên 1 và đồng thời user2 đến và tăng nó, giá trị sẽ là 2. Nó thực sự sẽ cho thấy rằng user1 có 1 và user2 có 1 (nếu đó là điều bạn định làm. Giỏ hàng ví dụ như trên).
Krishna

137

Đậu phiên không trạng thái (SLSB) không bị ràng buộc với một khách hàng và không có bảo đảm cho một ứng dụng khách nhận được cùng một phiên bản với mỗi lần gọi phương thức (một số vùng chứa có thể tạo và phá hủy các bean với mỗi phiên gọi phương thức, đây là quyết định dành riêng cho việc triển khai , nhưng các trường hợp thường được gộp chung - và tôi không đề cập đến các môi trường được phân nhóm). Nói cách khác, mặc dù các bean không trạng thái có thể có các biến cá thể, nhưng các trường này không dành riêng cho một máy khách, vì vậy đừng dựa vào chúng giữa các cuộc gọi từ xa.

Ngược lại, Stateful Session Beans (SFSB) dành riêng cho một ứng dụng trong suốt cuộc đời của họ, không có sự hoán đổi hoặc gộp các phiên bản (nó có thể bị xóa khỏi bộ nhớ sau khi thụ động để tiết kiệm tài nguyên nhưng đó là một câu chuyện khác) và duy trì trạng thái hội thoại . Điều này có nghĩa là các biến thể hiện của bean có thể giữ dữ liệu liên quan đến máy khách giữa các lần gọi phương thức. Và điều này làm cho khả năng có các cuộc gọi phương thức phụ thuộc lẫn nhau (các thay đổi được thực hiện bởi một phương thức sẽ ảnh hưởng đến các cuộc gọi phương thức tiếp theo). Các quy trình nhiều bước (quy trình đăng ký, giỏ hàng, quy trình đặt phòng ...) là các trường hợp sử dụng điển hình cho SFSB.

Một điều nữa. Nếu bạn đang sử dụng SFSB, thì bạn phải tránh đưa chúng vào các lớp có bản chất đa luồng, chẳng hạn như Servlet và các bean được quản lý JSF (bạn không muốn tất cả các máy khách chia sẻ nó). Nếu bạn muốn sử dụng SFSB trong ứng dụng web của mình, thì bạn cần thực hiện tra cứu JNDI và lưu trữ cá thể EJB đã trả về trong HttpSessionđối tượng cho hoạt động sau này. Đại loại vậy:

try {
    InitialContext ctx = new InitialContext();
    myStateful = (MyStateful)ctx.lookup("java:comp/env/MyStatefulBean");
    session.setAttribute("my_stateful", myStateful);
} catch (Exception e) {
    // exception handling
}

Cảm ơn vì đã làm sáng tỏ. Khi tôi sử dụng một chương trình dòng lệnh độc lập cho máy khách, có thể thấy rõ sự khác biệt.
Stanley kelly

cảm ơn cho ý kiến ​​của bạn, họ là sáng hơn. đầu tiên bạn đưa ra định nghĩa trừu tượng, sau đó chỉ định một số trường hợp sử dụng cho từng tình huống, và sau đó chỉ ra một số cạm bẫy. Tuyệt vời +1
arthur

Có phải phần tránh tiêm cũng bị loại bỏ đối với EJB 3.1 không?
jacktrades 14/12/12

7
@Pascal nếu "Stateful Session Beans (SFSB) dành riêng cho một khách hàng trong suốt cuộc đời của họ", tức là khả năng này được xây dựng trong SFSB, vậy tại sao cần lưu trữ chúng trên đối tượng HttpSession?
user1169587 Ngày

2
Tại sao chúng ta cần giữ trạng thái bean trong phiên nếu nó đã 'được đánh dấu'? Bằng cách này, chúng ta có thể làm cho mọi đối tượng được phân loại. Giải thích pls
Georgy Gobozov

18

Không trạng thái và trạng thái trong bối cảnh này không hoàn toàn có nghĩa là những gì bạn có thể mong đợi.

Tính trạng thái trong EJB đề cập đến cái mà tôi gọi là trạng thái hội thoại . Ví dụ điển hình là đặt vé máy bay. Nếu nó bao gồm ba bước:

  • Đặt chỗ
  • Tính phí thẻ tín dụng
  • Phát hành vé

Hãy tưởng tượng mỗi trong số đó là một cuộc gọi phương thức tới một session bean. Một bean phiên trạng thái có thể duy trì kiểu hội thoại này để nó ghi nhớ những gì xảy ra giữa các cuộc gọi.

Các hạt phiên không trạng thái không có khả năng như vậy cho trạng thái đàm thoại.

Các biến toàn cục bên trong một session bean (không trạng thái hoặc trạng thái) là một cái gì đó hoàn toàn khác. Các bean phiên trạng thái sẽ có một nhóm các bean được tạo (vì một bean chỉ có thể được sử dụng trong một cuộc hội thoại tại một thời điểm) trong khi các bean sesion không trạng thái thường chỉ có một phiên bản, điều này sẽ làm cho biến toàn cục hoạt động, nhưng tôi không nghĩ điều này nhất thiết phải đảm bảo.


5

Sự khác biệt chính giữa hai loại đậu chính là:

Đậu không trạng thái

  1. Các Đậu phiên không trạng thái là những Đậu không có trạng thái đối thoại với máy khách đã gọi các phương thức của nó. Vì lý do này, họ có thể tạo một nhóm các đối tượng có thể được sử dụng để tương tác với nhiều máy khách.
  2. Các hạt đậu không trạng thái khôn ngoan về hiệu suất tốt hơn vì chúng không có trạng thái cho mỗi khách hàng.
  3. Họ có thể xử lý song song nhiều yêu cầu từ nhiều máy khách.

Đậu trạng thái

  1. Các bean phiên trạng thái có thể duy trì trạng thái đàm thoại với nhiều máy khách cùng một lúc và nhiệm vụ không được chia sẻ giữa các máy khách.
  2. Sau khi phiên hoàn thành, trạng thái không được giữ lại.
  3. Hộp chứa có thể tuần tự hóa và lưu trữ trạng thái ở dạng để sử dụng trong tương lai. Điều này được thực hiện để tiết kiệm tài nguyên của máy chủ ứng dụng và hỗ trợ các lỗi bean.

4

Điều này xảy ra vì vùng chứa chỉ có một cá thể bean trong nhóm đang được sử dụng lại cho tất cả các cuộc gọi. Nếu bạn chạy các máy khách song song, bạn sẽ thấy một kết quả khác vì vùng chứa sẽ tạo ra nhiều cá thể bean hơn trong nhóm.


4

Nó có câu trả lời tốt. Tôi xin thêm câu trả lời nhỏ. Không nên sử dụng Stateless Bean để giữ bất kỳ dữ liệu khách hàng nào. Nó nên được sử dụng để "mô hình hóa các hành động hoặc quy trình có thể được thực hiện trong một lần".


4

Câu hỏi hay,

hãy thử mã này (thay đổi 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());
    }

}

trường hợp: 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

case: 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


1
Vâng, đó là Nó và Nó hoạt động! Giải thích rất dễ dàng, cảm ơn!
Nesquik27
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.