You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:07:42