2011-01-04 23 views
5

Tôi có hai phiên bản của hạt CDI SessionScoped cho cùng một phiên. Tôi đã ấn tượng rằng sẽ có một ví dụ được tạo ra cho tôi bởi CDI, nhưng nó tạo ra hai. Tôi có hiểu nhầm CDI hoạt động như thế nào không, hoặc tôi có tìm thấy lỗi không?Kết quả CDI SessionScoped Bean trong hai trường hợp trong cùng một phiên

Đây là mã đậu:

package org.mycompany.myproject.session; 

import java.io.Serializable; 
import javax.enterprise.context.SessionScoped; 
import javax.faces.context.FacesContext; 
import javax.inject.Named; 
import javax.servlet.http.HttpSession; 

@Named @SessionScoped public class MyBean implements Serializable { 
    private String myField = null; 

    public MyBean() { 
     System.out.println("MyBean constructor called"); 

     FacesContext fc = FacesContext.getCurrentInstance(); 
     HttpSession session = (HttpSession)fc.getExternalContext().getSession(false); 
     String sessionId = session.getId(); 
     System.out.println("Session ID: " + sessionId); 
    } 

    public String getMyField() { 
     return myField; 
    } 

    public void setMyField(String myField) { 
     this.myField = myField; 
    } 
} 

Đây là mã Facelet:

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core"> 
<f:view contentType="text/html" encoding="UTF-8"> 
    <h:head> 
     <title>Test</title> 
    </h:head> 
    <h:body> 
     <h:form id="form"> 
      <h:inputText value="#{myBean.myField}"/> 
      <h:commandButton value="Submit"/> 
     </h:form> 
    </h:body> 
</f:view> 
</html> 

Đây là kết quả từ việc triển khai và điều hướng đến trang:

INFO: Loading application org.mycompany_myproject_war_1.0-SNAPSHOT at /myproject 
INFO: org.mycompany_myproject_war_1.0-SNAPSHOT was successfully deployed in 8,237 milliseconds. 
INFO: MyBean constructor called 
INFO: Session ID: 175355b0e10fe1d0778238bf4634 
INFO: MyBean constructor called 
INFO: Session ID: 175355b0e10fe1d0778238bf4634 

Sử dụng GlassFish 3.0.1

+1

Tôi đã thực sự cảnh báo về vấn đề trên bằng một liên quan một: gọi một phương thức không chính thức trong một constructor (hoặc khối initializer) gây ảnh hưởng ngoài ý muốn với CDI. Tôi đã đọc rằng sử dụng một phương pháp không phải là cuối cùng không được thông báo (http://download.oracle.com/javase/tutorial/java/javaOO/initial.html). Nếu tôi sử dụng một phương thức không phải cuối cùng để intialize một List trong một CDI bean thì intitializer được gọi hai lần! Lưu ý: CDI không cho phép các phương thức cuối cùng và sẽ ném một ngoại lệ thời gian chạy cho biết rằng bean không được ủy quyền. "Sửa lỗi" không gọi phương thức không phải cuối cùng và thực hiện tất cả công việc trong khối initilizer. – Ryan

+0

Tôi đã nhận thấy rằng nếu tôi định nghĩa một phương thức init được chú thích bằng @PostConstruct thì nó chỉ được gọi một lần (mặc dù hai trường hợp của bean được tạo ra). Tôi đoán rằng CDI đang tạo ra một nhóm các cá thể của bean của tôi và gọi các post post khi nó kéo chúng ra khỏi pool. Tôi đoán việc kết hợp thể hiện của bean vẫn còn trong pool với phiên HTTP hiện tại là vô nghĩa. – Ryan

+1

Xem phản hồi của tôi bên dưới. 2 trường hợp thứ nhất là cá thể theo ngữ cảnh, thứ 2 là proxy. Các @PostConstruct sẽ tất nhiên chỉ nhận được gọi là cho ví dụ theo ngữ cảnh và _not_ cho proxy. – struberg

Trả lời

4

Ryan, như giao ước đã được viết, nhà xây dựng cũng sẽ được gọi cho mỗi và mọi proxy cho bean đó. Đây là một hành vi tiêu chuẩn của tất cả các cơ chế proxy cung cấp không chỉ giao diện-proxy (như java.lang.reflect.proxy thứ) nhưng thực lớp proxy.

Cũng hãy tưởng tượng rằng dấu ct cũng sẽ được gọi cho mỗi và từng chuỗi. Vì vậy, nếu bạn làm việc trên một cụm cân bằng tải nặng, bạn sẽ thấy rất nhiều lần. Vì vậy, hãy sử dụng @PostConstruct cho đậu nói chung.

LieGrue, Strub

+0

Cảm ơn bạn đã phản hồi. Tôi vẫn chưa hiểu cả hai. Tôi biết các cách thay thế để chuẩn bị một bean để sử dụng như cuộc gọi lại vòng đời PostConstruct và sự kiện hệ thống preRenderView; và điều đó thật tuyệt. Câu hỏi của tôi là tại sao hai trường hợp của một phiên scoped bean được tạo ra trong một thử nghiệm rất đơn giản với chỉ một người dùng nhấn máy chủ. Tôi không nói về một máy chủ tải nặng với cân bằng tải và phân cụm. Có nhiều hơn một proxy được tạo không? Nếu vậy, tại sao? Hoặc có thể mỗi proxy được hỗ trợ bởi hai phiên bản của bean? Nếu vậy, tại sao? – Ryan

+2

Ryan, tôi biết tất cả các công cụ proxy không phải là dễ dàng, nhưng nhận được 2 lời gọi constructor là hoàn toàn tốt đẹp. Ví dụ đầu tiên là chính cá thể theo ngữ cảnh.Đây là bean bạn sẽ được lưu trữ trong SessionContext. Ví dụ thứ hai là proxy. Nếu bạn nhìn kỹ với trình gỡ rối hoặc bạn in ra lớp trong hàm tạo, thì bạn sẽ thấy rằng đây là một lớp con của bean của bạn! – struberg

+0

Một là proxy và một là bean thực. Hiểu rồi. Có vẻ như bạn phải cẩn thận những gì bạn đặt trong một constructor khi sử dụng CDI. – Ryan

3

Khả năng thực thi CDI của bạn gọi hàm tạo mặc định của bean khi tạo proxy để sử dụng cho các điểm chèn - đây là hành vi mặc định của javassist được sử dụng trong mối hàn và openwebbeans.

Tránh nâng vật nặng trong nhà xây dựng mặc định của bạn, di chuyển nó vào @PostConstruct nếu bạn có thể!

+0

OK, nhưng tại sao hai được tạo ra? CDI có tạo ra một hồ bơi không? – Ryan

Các vấn đề liên quan