XPages中Java Beans数据存储与读取最佳实践及问题咨询
Java Bean 优化与问题解答
原代码
public class BeanMethods { private static final long serialVersionUID = 1L; public Database db; public ArrayList<String> userTabs; public BeanMethods() { db = ExtLibUtil.getCurrentDatabase(); userTabs = new ArrayList<String>(); } public ArrayList<String> getUserTabs(String uid) throws NotesException { if (userTabs.isEmpty()) { userTabs = getUserTabs2(uid); } return userTabs; } public ArrayList<String> getUserTabs2(String uid) throws NotesException { db = ExtLibUtil.getCurrentDatabase(); String key = "TAB_UID_" + uid; DocumentCollection dc = db.getView("LookupKey").getAllDocumentsByKey(key, true); Document d = dc.getFirstDocument(); while (d != null) { String tabTitle = d.getItemValueString("Title"); userTabs.add(tabTitle + "|" + d.getItemValueString("UniqueId")); d = dc.getNextDocument(d); } return userTabs; } }
问题解答
1. 如何在运行时更新userTabs属性?
新增一个公开的刷新方法,清空原有缓存后重新加载最新数据即可:
public void refreshUserTabs(String uid) throws NotesException { userTabs.clear(); getUserTabs2(uid); }
调用这个方法后,后续调用getUserTabs就会返回最新的标签列表。由于Bean处于sessionScope,该操作只会影响当前用户的缓存数据。
2. 构造方法中设置的db变量无法始终保持,哪里考虑不周?
核心问题在于Notes对象的生命周期限制:
- Database对象与当前会话/请求上下文绑定,构造方法仅在Bean初始化时执行一次,后续会话中原有db对象可能已失效(比如连接回收、会话状态变更),无法正常使用。
- 你将db设为public成员变量,存在被外部篡改的风险,进一步加剧了对象失效的概率。
正确做法:不要把Database作为成员变量缓存,而是在需要访问数据库的方法内,通过ExtLibUtil.getCurrentDatabase()实时获取有效实例;同时将成员变量的访问权限改为private,避免外部干预。
3. 是否有更优的代码编写方式?
有多个关键优化点,优化后的代码如下:
public class BeanMethods implements Serializable { private static final long serialVersionUID = 1L; // 用Map缓存不同用户的标签,避免多用户缓存混淆 private final Map<String, List<String>> userTabCache = new HashMap<>(); public List<String> getUserTabs(String uid) throws NotesException { if (!userTabCache.containsKey(uid)) { userTabCache.put(uid, loadUserTabs(uid)); } // 返回缓存的副本,防止外部修改缓存内的数据 return new ArrayList<>(userTabCache.get(uid)); } // 公开刷新方法,支持运行时更新 public void refreshUserTabs(String uid) throws NotesException { userTabCache.put(uid, loadUserTabs(uid)); } // 内部加载数据的方法,封装逻辑且不对外暴露 private List<String> loadUserTabs(String uid) throws NotesException { List<String> tabs = new ArrayList<>(); Database db = ExtLibUtil.getCurrentDatabase(); View lookupView = db.getView("LookupKey"); // 增加视图存在性检查,避免空指针 if (lookupView == null) { throw new NotesException("视图 'LookupKey' 不存在"); } String key = "TAB_UID_" + uid; DocumentCollection dc = lookupView.getAllDocumentsByKey(key, true); Document doc = dc.getFirstDocument(); try { while (doc != null) { String tabTitle = doc.getItemValueString("Title"); String uniqueId = doc.getItemValueString("UniqueId"); tabs.add(tabTitle + "|" + uniqueId); Document nextDoc = dc.getNextDocument(doc); doc.recycle(); // 手动回收Notes文档对象,避免内存泄漏 doc = nextDoc; } } finally { // 回收文档集合和视图资源 if (dc != null) dc.recycle(); if (lookupView != null) lookupView.recycle(); } return tabs; } }
主要优化点:
- 缓存逻辑修正:用
Map<String, List<String>>区分不同用户的标签,解决原代码中uid切换后返回错误缓存的问题。 - 资源回收:手动回收Notes的Document、DocumentCollection、View对象,避免内存泄漏。
- 封装性提升:把加载逻辑封装到private方法,成员变量设为private,对外只暴露必要的方法。
- 安全性增强:返回缓存的副本,防止外部代码直接修改缓存内容;增加视图存在性检查,提前抛出异常。
- 去除无效缓存:不再缓存Database对象,每次方法内实时获取有效实例。
内容的提问来源于stack exchange,提问作者Thomas Adrian
相关产品推荐
相关产品推荐

