编辑:评论部分解决了我的问题!问题是我对Scopes使用了错误的导入.
我有一个简单的JSF应用程序(登录,从数据库中提取数据,允许用户编辑数据).它运行良好,我想更新代码使用CDI(Weld),但我遇到了麻烦.
我正在关注/查看:http://docs.jboss.org/weld/reference/latest/en-US/html/example.html
没有Weld的原始东西:
login.xhtml
<h:form id="inputForm">
<h:panelGrid columns="2" cellpadding="5" cellspacing="1">
<h:outputText id="nameDesc" value="Name"></h:outputText>
<h:inputText id="nameInput" value="#{login.loginName}" binding="#{name}"></h:inputText>
<h:outputText id="passwordDesc" value="Password"></h:outputText>
<h:inputSecret id="passwordInput" value="#{login.password}" binding="#{password}"></h:inputSecret>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login(name.value, password.value)}"/>
</h:form>
LoginBean.java:
@ManagedBean(name="login")
@SessionScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L;
@ManagedProperty(value="#{db}")
private DatabaseBean db;
private String password;
private String loginName;
// other stuff and functions
public String getLoginName () {
return loginName;
}
public void setLoginName (String name) {
this.loginName = name;
}
public String getPassword () {
return password;
}
public void setPassword (final String password) {
this.password = password;
}
public void setDb(DatabaseBean db) {
this.db = db;
}
DatabaseBean.java:
@ManagedBean(name="db", eager=true)
@ApplicationScoped
public class DatabaseBean implements Serializable {
@PostConstruct
public void init() {
//... connect to database etc
}
}
———我试图让它与Weld一起运行(仅从上面进行更改以使其更短):——–
LoginBean.java,从@ManagedBean更改为@Named,为DatabaseBean添加了@Inject
@Named("login")
@SessionScoped
public class LoginBean implements Serializable {
// stuff
private @Inject DatabaseBean db;
}
DatabaseBean.java,从@ManagedBean更改为@Named:
@Named("db")
@ApplicationScoped
public class DatabaseBean implements Serializable {
}
LoginBean有一个函数:
public String login(String name, String password) {
System.out.println("login called"+name);
// other stuff
}
在我的第二个实现(我尝试使用Weld的那个)中,print被调用一次:“login called”,用户名为空(我用name.IsEmpty()检查了它).
我也尝试过构造函数注入它:
loginBean.java
@Inject
public LoginBean(DatabaseBean db) {
System.out.println("constructor");
this.db = db;
}
当我这样做时,我得到了很多“构造函数”打印,因此它被调用了好几次,但我不明白为什么 – 我想这是问题,但只有一个LoginBean实例获取输入(用户名和密码)然后由于某种原因创建了许多新的.这是为什么?
我使用Eclipse和Tomcat8来运行它.
谢谢你的阅读!
最佳答案
managed bean constructor called multiple times
在生成/创建增强的子类/代理时,CDI可能比预期更频繁地调用构造函数.另请参见Field.get(obj) returns all nulls on injected CDI managed beans, while manually invoking getters return correct values.只是不要记录构造函数调用,它只会让自己感到困惑. @PostConstruct是唯一有趣的方法.
the print is called once: “login called”, and the username is empty (I checked this with name.IsEmpty()).
至于调用action方法时表单输入值为null的具体问题,因此@SessionScoped CDI托管bean似乎在每次访问时都会重新创建,这与@Dependent作用域bean的行为相匹配.当找不到有效的CDI托管bean作用域时,这是默认作用域.另见What is the default Managed Bean Scope in a JSF 2 application?
这反过来表明您从错误的包中导入了@SessionScoped.确保它来自javax.enterprise.context包,而不是来自例如javax.faces.bean. JSF托管bean作用域无法识别为有效的CDI托管bean作用域.
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
@Named("login")
@SessionScoped
public class LoginBean implements Serializable {
// ...
}