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

Java中如何将ResourceBundle对象存储到Session中

ResourceBundle存Session序列化警告修复方案

警告原因

Java EE规范要求HttpSession中存储的所有属性必须实现Serializable接口,触发会话持久化(集群部署会话同步、服务器停机会话落盘等场景)时会直接抛出NotSerializableException异常。你当前功能正常只是因为还没触发这类会话持久化逻辑,生产环境存在隐忧。

最优解决方案:不直接存储ResourceBundle实例

你完全不需要把整个ResourceBundle对象存入Session,JDK本身对ResourceBundle有全局缓存,重复调用ResourceBundle.getBundle()不会有额外性能损耗。你只需要存入构造ResourceBundle需要的两个可序列化参数Locale和basename即可,修改逻辑如下:

  1. 修改BundleHandler代码,不再存ResourceBundle,仅存可序列化的basename到Session:
public class BundleHandler extends SimpleTagSupport {
    private String basename;

    public void setBasename(String basename) {
        this.basename = basename;
    }
    @Override
    public void doTag() {
        PageContext pageContext = (PageContext)getJspContext();
        HttpSession session = pageContext.getSession();
        session.setAttribute("bundleBasename", basename);
    }
}
  1. 调整localeValue、LValueParam两个标签的取值逻辑,每次读取国际化值时实时获取ResourceBundle:
    以localeValue标签为例,修改后代码如下:
public class LocalValueHandler extends SimpleTagSupport {
    private String key;

    public void setKey(String key) {
        this.key = key;
    }

    @Override
    public void doTag() throws Exception {
        PageContext pageContext = (PageContext) getJspContext();
        HttpSession session = pageContext.getSession();
        Locale locale = (Locale) session.getAttribute("tagLocale");
        String basename = (String) session.getAttribute("bundleBasename");
        // 实时获取ResourceBundle,JDK内置缓存无性能损耗
        ResourceBundle bundle = ResourceBundle.getBundle(basename, locale);
        String value = bundle.getString(key);
        getJspContext().getOut().write(value);
    }
}

该方案完全规避了非序列化对象存Session的问题,无性能损失,兼容性最好。

备选方案:封装可序列化的资源包实例

如果确实需要预加载资源包存入Session,可以自己实现一个可序列化的包装类,把ResourceBundle的内容转存到序列化的Map中:

import java.io.Serializable;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

public class SerializableResourceBundle implements Serializable {
    private final Map<String, String> resourceMap = new HashMap<>();

    public SerializableResourceBundle(ResourceBundle originalBundle) {
        Enumeration<String> keys = originalBundle.getKeys();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            resourceMap.put(key, originalBundle.getString(key));
        }
    }

    public String getString(String key) {
        return resourceMap.get(key);
    }
}

存Session时用该类包装原始ResourceBundle即可:

ResourceBundle originalBundle = ResourceBundle.getBundle(basename,gotLocale);
session.setAttribute("Bundle", new SerializableResourceBundle(originalBundle));

临时解决方案:屏蔽警告(不推荐)

如果确认你的应用永远不会用到会话持久化、不会做集群部署,可以直接给对应代码加上注解抑制IDE警告:

@SuppressWarnings("NonSerializableObjectBoundToHttpSession")
session.setAttribute("Bundle",bundle);

该方案仅屏蔽警告,未解决实际问题,生产环境不建议使用。


内容的提问来源于stack exchange,提问作者DozezQuest

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 05:06:04