【问题标题】:Managed Java bean gets re-initialized at EVERY complete refresh or page reload每次完全刷新或页面重新加载时,托管 Java bean 都会重新初始化
【发布时间】:2014-07-22 21:49:45
【问题描述】:

在我的 XPages 应用程序中,我使用托管 Java bean (scope = application) 来翻译字符串:

public class Translator extends HashMap<String,String> implements Serializable {

    private static final long serialVersionUID = 1L;
    public String language = "en";

    public Translator() { super(); this.init(null); }
    public Translator(String language) { super(); this.init(language); }

    public boolean init(String language) {
        try {           
            FacesContext context = FacesContext.getCurrentInstance();
            if (language!=null) this.language=language;
            Properties data = new Properties();

            // load translation strings from properties file in WEB-INF
            data.load(new InputStreamReader(context.getExternalContext().getResourceAsStream("WEB-INF/translations_"+this.language+".properties"),"UTF-8"));
            super.putAll(new HashMap<String,String>((Map) data));

            // serializing the bean to a file on disk > this part of the code is just here to easily test how often the bean is initialized
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\\dump\\Translator_"+this.language+"_"+new Date().getTime()+".ser"));
            out.writeObject(this);
            out.close();

            return true;
        }
        catch (Exception e) { return false; }
    }

    public String getLanguage() { return this.language; }
    public boolean setLanguage(String language) { return this.init(language); }

    // special get function which is more tolerant than HashMap.get
    public String get(Object key) {
        String s = (String) key;
        if (super.containsKey(s)) return super.get(s);
        if (super.containsKey(s.toLowerCase())) return super.get(s.toLowerCase());
        String s1 = s.substring(0,1);
        if (s1.toLowerCase().equals(s1)) {
            s1=super.get(s1.toUpperCase()+s.substring(1));
            if (s1!=null) return s1.substring(0,1).toLowerCase()+s1.substring(1);
        } else {
            s1=super.get(s1.toLowerCase()+s.substring(1));
            if (s1!=null) return s1.substring(0,1).toUpperCase()+s1.substring(1);           
        }
        return s;
    }
}

我使用“extends HashMap”,因为这样我只需编写“${myTranslatorBean['someText']}”(表达式语言)就可以将翻译输入我的 XPage。问题是 bean 在 EVERY 完全刷新或页面重新加载时重新初始化。我通过在每次初始化结束时将 bean 序列化为磁盘上的唯一文件来测试这一点。在我的其他托管 Java bean(不使用“扩展 HashMap”)中,不会发生此问题。谁能告诉我我的代码有什么问题?提前致谢。


编辑:faces-config.xml 中托管 Java bean 的条目如下所示:

  <managed-bean>
    <managed-bean-name>myTranslatorBean</managed-bean-name>
    <managed-bean-class>com.ic.Translator</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
  </managed-bean>

【问题讨论】:

  • 如何用“语言”参数实例化 bean?
  • @FrantisekKossuth:这里提供的代码已经缩小,以包含尽可能少的错误源。在完整的类中,当调用空构造函数时(对于托管 bean 的情况),语言是根据上下文中的当前语言环境确定的。当我需要在代码中的某个地方使用自定义翻译器时,我会使用带有语言作为参数的构造函数。如果要将变量传递给托管 bean,则必须在 faces-config.xml 中声明一个“托管属性”。
  • 我的问题完全是关于你发现了什么(并在接受的答案下方评论) - 你必须在某个地方调用 init() ...

标签: xpages


【解决方案1】:

我同意 David 关于 faces-config 条目的观点 - 如果您可以发布它,那可能会有所启发。

在它缺席的情况下,我会尝试一下:您是否使用托管属性来设置应用程序的“语言”值。如果是,我怀疑运行时很有可能过度调用 setLanguage(...) 方法。由于您在该方法中调用 this.init(...),因此也会重复重新运行该方法。

作为一种你可以随意忽略的代码风格,随着时间的推移,我(部分是由于阅读了其他人的意见)已经不再直接扩展集合类以用于这种用途。在这种情况下,我所做的是创建一个实现 DataObject 接口的对象,然后在内部使用 HashMap 来存储缓存值。这是一个更大的行业偏好的一部分,称为“组合优于继承”:http://en.wikipedia.org/wiki/Composition_over_inheritance

【讨论】:

  • 感谢您的建议:在我的测试 XPage 的一个计算字段中,我使用了 myTranslatorBean.setLanguage("en") - 所以显然 bean 在每次刷新时都会重新初始化。我看了几个小时的代码,我不知道为什么我没有马上看到。谢谢你让我大开眼界:)
【解决方案2】:

只是为了确保没有什么奇怪的 - 我建议你发布你的 faces-config。我一直在使用 bean,但没有在其中任何一个中扩展 HashMap。您可以添加地图并仍然使用 EL。

假设您有一个像“getMyMap()”这样的地图获取器,那么 EL 可能是:

AppBean.myMap["myKey"]

说实话,我通常不使用这种语法,但我相信它有效。我给了它一个快速测试,它没有按我的预期工作,所以我遗漏了一些东西。我试过类似的东西: imageData.size["大"].url

我认为它对我不起作用,因为我的 bean 没有实现 Map。我注意到您正在扩展 HashMap。您可能想尝试实现它。我在这里发现了一个有趣的帖子:http://blog.defrog.nl/2012/04/settings-bean-parameterized-method-call.html

通常我仍然使用 SSJS 来传递参数。这真的不是使用 SSJS 的结束。我将 EL 用于其他一切。

这是一个将对象传递给自定义控件并返回带有 EL 的 TreeSet 的示例。

value="#{compositeData.imageSet.allImages}">

关于 bean 重新初始化的更大问题..这很奇怪..我没有用 ApplicationScope 做很多事情。但我建议你使用构造函数。我不确定在那里调用 super() 会得到什么。我建议使用布尔值仅运行尚未设置的布尔值的任何初始化代码。显然,您随后将其设置在初始化代码中。看看有什么作用。

【讨论】:

  • 感谢您的回答。不幸的是,问题不在于 bean 本身。是我在我的测试 XPage 的计算字段中调用 Translator bean 的 setLanguage() 方法。很抱歉浪费您的时间。 PS:我没有使用您链接的博客中建议的方法的原因是我想使用 myTranslatorBean["someText"] 而不是 myTranslatorBean.value["someText"]。只是为了让 XPage 更易读 :)
猜你喜欢
  • 1970-01-01
  • 2020-06-17
  • 1970-01-01
  • 1970-01-01
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
相关资源
最近更新 更多