JSF Managed bean 中 List 的初始化
Posted
技术标签:
【中文标题】JSF Managed bean 中 List 的初始化【英文标题】:Initialization of List in a JSF Managed bean 【发布时间】:2013-03-24 07:01:33 【问题描述】:我有一个关于 POJO 中 List 初始化的问题,因为它遵循下一个代码:
public class Person
//other fields...
private List<String> friends=new ArrayList<>();
public List<String> getFriends()
return friends;
public void setFriends(List<String> friends)
this.friends = friends;
或者像这样更好并且在其他类中有初始化(例如 Bean(JSF))
public class Person
//other fields...
private List<String> friends;
public List<String> getFriends()
return friends;
public void setFriends(List<String> friends)
this.friends = friends;
所以我的问题是哪种方法更好?
【问题讨论】:
如果他们先调用 getter,你就完蛋了。 是managedBean
吗?
@Eng.Fouad 是的,它是 managedBean。
@kolossus 我们以前不知道这是一个托管 bean。鉴于新信息,我同意,因此删除了我的评论。
实际上,您不需要一直依赖@PostConstruct
。仅当且仅当您需要等待某些依赖注入完成时才需要该注释,以便您可以使用某些服务来初始化列表。如果不是,那么您在问题中所做的一切都很好:)。但是,我确实有一种不好的感觉,即您当前的架构不是最佳实践。数据库中是否有任何名为 Person
的实体?
【参考方案1】:
在我看来,最好在构造函数中处理它。如果使用默认构造函数,则在构造函数中初始化列表。
public Person()
friends = new ArrayList<>();
如果使用接受参数的构造函数,让调用类传入一个列表。
public Person(ArrayList<> friends)
this.friends = friends;//friends
【讨论】:
在托管 bean 中,最好不要在构造函数中处理此问题 是的,我的示例更适合 POJO 而不是托管 bean。尽管我认为如果您不使用托管属性,则在默认的无参数构造函数中使用托管 bean 进行初始化不会有任何危害。 因为这是一个基本示例,所以它会起作用。但是,正如在 kolossus 答案的第 3 节中发布的那样,托管 bean 上的所有注入字段(如@EJB
、@ManagedProperty
等)都不会在类构造函数中起作用,而是在 @PostConstruct
方法中起作用。跨度>
【参考方案2】:
这取决于。通常第一种方式更可取,因为您可能希望稍后将某些内容添加到集合中。如果您不知道您的集合是否已初始化,您必须每次都检查它。
【讨论】:
【参考方案3】:我建议这样做:
public class Person
//other fields...
private List<String> friends=new ArrayList<>();
// returns a copy to protect original list
public List<String> getFriends()
Collections.unmodifiableList(new ArrayList<>(friends));
public void addFriend(String> friend)
this.friends.add(friend);
public void addFriends(List<String> friends)
this.friends.addAll(friends);
【讨论】:
您可能想要clear
或在set
中做一个防御性副本,否则它不是真正的二传手,而是addAll
。
@bmorris591:谢谢我更改了方法名称以避免混淆。
与我自己的答案非常相似,但总体上可能会更好地设计有这样的 add 和 addAll 方法。我怀疑我们同时打字。 +1【参考方案4】:
我的建议,在getter中添加一个空检查:
public class Person
//other fields...
private List<String> friends;
public List<String> getFriends()
if (this.friends == null) friends = new ArrayList<String>();
return friends;
但也请注意我省略了 setter。相反,在任何客户端代码中,调用如下:
personInstance.getFriends().add("Some Item");
或者,如果您有完整的列表要添加:
personInstance.getFriends().addAll(someStringCollection);
【讨论】:
取决于 OP 希望的行为。这是一种被称为“延迟初始化”的好策略。如果这是一个托管 bean,您还需要一个无参数构造函数。【参考方案5】:如果它是你所说的托管 bean,你应该在一个带有 @PostConstruct
注释的方法中执行此操作
public class Person
private List<String> friends;
@PostConstruct
public void init()
friends = new ArrayList<String>();
//getter and setter...
在 JSF 的上下文中通常不赞成在 getter 和 setter 中进行任何初始化的做法。见Why JSF calls getters multiple times
另外,per the API for @PostConstruct
,合同规定了安全特性,并保证如果在这样注释的方法中抛出异常,则不应将 bean 投入使用。普通构造函数没有这样的保证。
在托管 bean 中,注入在构造后立即发生。这意味着您在构造函数中执行的任何操作都不能依赖于任何注入的资源(通过@ManagedProperty
)。而在 @PostConstruct
方法中,您将可以访问托管 bean 上声明的所有资源
编辑:重要的是要注意只有一个@PostConstruct
可以用于任何@ManagedBean
,所以所有重要的初始化都应该在那里进行。
还值得注意的是,虽然@PostConstruct
方法是初始化支持 bean 变量/List
的理想位置,但它对托管 bean 的范围有一些影响
@RequestScoped
:在带有此注解的托管 bean 中,每次提交相关的 JSF 视图都会调用该方法。 @RequestScoped
bean 在每次请求时都会被销毁并重新创建,这意味着根据您的设置,在 @PostConstruct
中初始化的列表可能会在每次请求期间重置为空值或默认值。在某些情况下,由于重新初始化 list mid-JSF 请求,可能会出现转换错误。
@ViewScoped
:在带有此注解的托管 bean 中,保证@PostConstruct
方法运行一次,当且仅当您正在处理相同的问题@ViewScoped
bean 的实例。如果 viewscoped bean 被销毁并重新创建,@PostConstruct
方法将再次运行。
@SessionScoped
:带有此注解的 bean 被创建一次,并一直保持活动状态,直到用户的 HTTP 会话结束。在这种情况下,@PostConstruct
方法保证运行一次,并且只运行一次,直到 bean 被销毁
另见
https://***.com/a/3406631/1530938【讨论】:
请不要编辑我引用的链接。我需要它作为元参考 值得在您的答案中添加此内容(直接来自@PostConstruct
文档):此注释只能注释一个方法。
像往常一样在 JSF 方面做得很好,但在这种情况下,我认为绝对没有理由在构造函数或初始化块上使用 @PostConstruct
。首先,我建议最好仅出于使用具有相关注释的初始化依赖项的目的使用 post 构造方法。我建议在构造函数或初始化程序块中独立于注入的依赖项初始化 bean 属性,因为它们自然属于那里。以上是关于JSF Managed bean 中 List 的初始化的主要内容,如果未能解决你的问题,请参考以下文章
CAS认证后在JSF Managed Bean中获取LDAP属性
JSF Managed Beans 不使用 spring 安全过滤器