Mam dwie instancje bean komponentu CDI SessionScoped dla tej samej sesji. Miałem wrażenie, że CDI wygeneruje jedną instancję, ale wygeneruje dwa. Czy nie rozumiem, jak działa CDI, czy też znalazłem błąd?SessionScoped Bean CDI powoduje dwie instancje w tej samej sesji
Oto kod fasola:
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;
}
}
Oto kod 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>
Tutaj jest wyjście z wdrożeniem i przechodząc do strony:
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
Korzystanie GlassFish 3.0.1
I faktycznie zaalarmowane powyższego problemu przez związane z nich: wywołanie nie Ostatnia metoda konstruktor (lub blok inicjatora) powoduje niezamierzone działania CDI. Odtąd czytałem, że nie zaleca się korzystania z metody nie ostatecznej (http://download.oracle.com/javase/tutorial/java/javaOO/initial.html). Jeśli użyję nieostatecznej metody do zainicjowania listy w komponencie CDI, to inicjator zostanie wywołany dwa razy! Uwaga: CDI nie zezwala na ostateczne metody i rzuci wyjątek Runtime stwierdzający, że komponent bean nie jest proxy. "Poprawka" nie wywołuje metody nieostatecznej i wykonuje wszystkie prace w bloku initilizer. – Ryan
Zauważyłem, że jeśli zdefiniuję metodę init opisaną przez @PostConstruct, to jest ona wywoływana tylko raz (pomimo dwóch instancji tworzonego komponentu bean). Zgaduję, że CDI tworzy pulę instancji mojego komponentu bean i wywołuje konstrukcję postu, ponieważ wyciąga je z puli. Przypuszczam, że powiązanie instancji komponentu bean, który nadal znajduje się w puli z bieżącą sesją HTTP, jest bez znaczenia. – Ryan
Zobacz moją odpowiedź poniżej. 2 instancje 1 to instancja kontekstualna, 2 to proxy. @PostConstruct będzie oczywiście wywoływany tylko dla kontekstowej instancji i _nie_ dla proxy. – struberg