将Apache Velocity与StringBuilders / CharSequences一起使用

时间:2011-03-07 12:20:58

标签: java apache string memory-management velocity

我们正在使用Apache Velocity来生成动态模板。目前,Velocity有以下评估/替换方法:

public static boolean evaluate(Context context, Writer writer, String logTag, Reader reader)

public static boolean evaluate(Context context, Writer out, String logTag, String instring)

我们通过提供StringWriter来编写评估结果来使用这些方法。我们的传入数据采用StringBuilder格式,因此我们使用StringBuilder.toString并将其作为instring提供。

问题是我们的模板相当大(在极少数情况下可能是兆字节,数十个Ms),频繁更换并且每次替换操作三倍所需内存量(传入数据+ StringBuilder.toString()创建新副本+传出数据。

我想知道是否有办法改善这一点。例如。如果我能找到一种方法在同一个Reader实例之上提供WriterStringBuilder,只为进/出差异使用额外的内存,这会是一个好方法吗?有没有人做过类似的事情,可以分享这类课程的任何来源?或者对于给定问题可能有更好的解决方案吗?

3 个答案:

答案 0 :(得分:2)

Velocity需要解析整个模板才能进行评估。您将无法在单次评估中提供ReaderWriter来获取任何内容。但是,您可以将模板分解为更小的部分,以便单独评估它们。这将取决于它们中的内容以及这些部分是否相互依赖。根据您的情况,开销可能不值得。

如果您只在模板中处理变量替换,则可以简单地评估输入的每一行。理想情况下,您可以在进入StringBuilder之前拦截它。否则,您仍然需要支付该内存的费用加上toString()的{​​{1}}费用,以便BufferedReader拨打readLine()电话。

如果有#set个指令,您需要继续传递相同的上下文以进行评估。如果有任何#if#foreach块,那将会变得棘手。我之前实际上已经完成了这项工作并读取了足够的行来捕获Velocity的输入块以进行解析和评估。那时候你开始做Velocity的工作,这可能不值得。

答案 1 :(得分:1)

您可以通过反映value中的StringBuilder字段并在其上创建CharArrayReader来保存该字符串的一个副本:

    StringBuilder sb = new StringBuilder("bla");
    Field valueField = StringBuilder.class.getSuperclass().getDeclaredField("value");
    valueField.setAccessible(true);
    char[] value = (char[]) valueField.get(sb);
    Reader r = new CharArrayReader(value, 0, sb.length());

答案 2 :(得分:0)

让人惊讶。这对于evaluate()来说非常重要。我假设你有充分的理由不使用标准资源加载器的东西,所以我不会教诲。 :)

我还没有听说过任何适合这种情况的解决方案,但由于Reader不是一个特别复杂的类,我的本能就是创建自己的StringBufferReader类并将其传入。

相关问题