此Java教程适用于JDK 8。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
有关Java SE 9及其后续版本中更新的语言功能的概述,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或不推荐使用选项的信息,请参阅JDK发行说明。
评估包括系统级别的应用程序可用内存量,是否接受和处理来自不受信任的源的XML、XSD或XSL源,以及应用程序级别的是否使用了DTD等构造。
XML处理可能需要非常多的内存。应该允许消耗的内存量取决于特定环境中应用程序的需求。必须防止处理格式错误的XML数据时消耗过多的内存。
默认限制通常设置为允许大多数应用程序的合法XML输入,并允许在小型硬件系统(如PC)上使用内存。建议将限制设置为最小可能值,以便在消耗大量内存之前捕获任何格式错误的输入。
这些限制是相关的,但并非完全冗余。您应该为所有限制设置适当的值:通常,限制应设置为比默认值小得多的值。
例如,可以设置ENTITY_EXPANSION_LIMIT和GENERAL_ENTITY_SIZE_LIMIT来防止过多的实体引用。但是,如果不知道扩展和实体大小的确切组合,TOTAL_ENTITY_SIZE_LIMIT可以作为总体控制。同样,TOTAL_ENTITY_SIZE_LIMIT控制替换文本的总大小,如果文本是一个非常大的XML块,ENTITY_REPLACEMENT_LIMIT设置对文本中可以出现的节点总数的限制,以防止过载系统。
为了帮助您分析应为限制设置什么值,有一个特殊的属性叫做http://www.oracle.com/xml/jaxp/properties/getEntityCountInfo可用。以下代码片段显示了使用该属性的示例:
parser.setProperty("http://www.oracle.com/xml/jaxp/properties/getEntityCountInfo", "yes");
有关下载示例代码的更多信息,请参阅示例。
当使用W3C MathML 3.0中的DTD运行程序时,它会打印出以下表格:
属性 | 限制 | 总大小 | 大小 | 实体名称 |
---|---|---|---|---|
ENTITY_EXPANSION_LIMIT | 64000 | 1417 | 0 | null |
MAX_OCCUR_NODE_LIMIT | 5000 | 0 | 0 | null |
ELEMENT_ATTRIBUTE_LIMIT | 10000 | 0 | 0 | null |
TOTAL_ENTITY_SIZE_LIMIT | 50000000 | 55425 | 0 | null |
GENERAL_ENTITY_SIZE_LIMIT | 0 | 0 | 0 | null |
PARAMETER_ENTITY_SIZE_LIMIT | 1000000 | 0 | 7303 | %MultiScriptExpression |
MAX_ELEMENT_DEPTH_LIMIT | 0 | 2 | 0 | null |
MAX_NAME_LIMIT | 1000 | 13 | 13 | null |
ENTITY_REPLACEMENT_LIMIT | 3000000 | 0 | 0 | null |
在这个例子中,实体引用的总数,或实体扩展,为1417;默认限制为64000。所有实体的总大小为55425;默认限制为50000000。最大的参数实体是%MultiScriptExpression,在解析所有引用后长度为7303;默认限制为1000000。
如果这是应用程序预期处理的最大文件,建议将限制设置为较小的数字。例如,ENTITY_EXPANSION_LIMIT为2000,TOTAL_ENTITY_SIZE_LIMIT为100000,PARAMETER_ENTITY_SIZE_LIMIT为10000。
限制可以像其他JAXP属性一样进行设置。可以通过工厂方法或解析器进行设置:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setAttribute(name, value); SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser parser = spf.newSAXParser(); parser.setProperty(name, value); XMLInputFactory xif = XMLInputFactory.newInstance(); xif.setProperty(name, value); SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage); schemaFactory.setProperty(name, value); TransformerFactory factory = TransformerFactory.newInstance(); factory.setAttribute(name, value);
以下示例演示如何使用DocumentBuilderFactory设置限制:
dbf.setAttribute(JDK_ENTITY_EXPANSION_LIMIT, "2000"); dbf.setAttribute(TOTAL_ENTITY_SIZE_LIMIT, "100000"); dbf.setAttribute(PARAMETER_ENTITY_SIZE_LIMIT, "10000"); dbf.setAttribute(JDK_MAX_ELEMENT_DEPTH, "100");
如果无法更改代码,系统属性可能很有用。
要为整个JDK或JRE的调用设置限制,请在命令行上设置系统属性。要仅为应用程序的一部分设置限制,可以在该部分之前设置系统属性,并在之后清除。以下代码显示了如何使用系统属性:
public static final String SP_GENERAL_ENTITY_SIZE_LIMIT = "jdk.xml.maxGeneralEntitySizeLimit"; //使用系统属性设置限制 System.setProperty(SP_GENERAL_ENTITY_SIZE_LIMIT, "2000"); //此设置将影响设置之后的所有处理 ... //完成后,清除属性 System.clearProperty(SP_GENERAL_ENTITY_SIZE_LIMIT);
请注意,属性的值应为整数。如果输入的值不包含可解析的整数,则会抛出NumberFormatException;请参阅方法parseInt(String)
。
有关下载示例代码的更多信息,请参阅示例。
jaxp.properties文件是一个配置文件。它通常位于${java.home}/lib/jaxp.properties,其中java.home是JRE的安装目录,例如,[安装目录的路径]/jdk8/jre。
可以通过将以下行添加到jaxp.properties文件中来设置限制:
jdk.xml.maxGeneralEntitySizeLimit=2000
请注意,属性名称与系统属性的名称相同,并具有前缀jdk.xml。属性的值应为整数。如果输入的值不包含可解析的整数,则会抛出NumberFormatException;请参阅方法parseInt(String)
。
当在文件中设置属性时,所有JDK和JRE的调用都将遵守该限制。