提问人:likeGreen 提问时间:8/31/2023 更新时间:8/31/2023 访问量:78
根据静态块与非静态块中的给定 xsd 验证 xml
Validate xml against a given xsd in static block vs non-static
问:
我有两种方法可以根据存储在旧应用程序资源中的 xsd 验证我的 xml。每天进行 1000+ 次验证,代码 24*7 全天候运行。
方法1: 是创建静态 SchemaFactory
public class XmlValidator {
private static final SchemaFactory schemaFactory;
static {
schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI, "com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", ClassLoader.getSystemClassLoader()); // This is done because of conflict due to xerces from //external jar and from Java
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
}
public boolean validateXmlWithXsd(String inputXml, String xsd) {
try (InputStream stream = new ByteArrayInputStream(xsd.getBytes(StandardCharsets.UTF_8));
StringReader reader = new StringReader(inputXml)) {
Source schemaFile = new StreamSource(stream);
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Source source = new StreamSource(reader);
validator.validate(source);
return true; // Validation successful
} catch (Exception e) {
// Handle validation errors here
e.printStackTrace();
return false; // Validation failed
}
}
}
方法2:(只需更改方法validateXmlWithXsd而不使用静态块)
public boolean validateXmlWithXsd (String inputXml, String xsd) {
try{
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI, "com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", ClassLoader.getSystemClassLoader())
InputStream stream = new ByteArrayInputStream (xsd.getBytes(StandardCharsets.UTF_8));
Source schemaFile = new StreamSource(stream);
Schema schema = schemaFactory.newSchema(schemaFile);
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Validator validator = schema. newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Source source = new StreamSource(new StringReader (inputXml)):
validator.validate(source);
}
}
我的想法: 使用系统类加载器调用 SchemaFactory.newInstance,尤其是在长时间运行的线程中重复调用(在 24*7 方案中 1000 次 + 时),可能会导致性能问题,并且可能不是最有效的方法。主要是由于类加载开销。所以,我更喜欢方法 1。另外,在静态 SchemaFactory 的情况下,我认为它有助于内存:
单个实例:当我声明一个静态 SchemaFactory 时,它只有一个实例在所有类实例之间共享。这意味着只创建一次 SchemaFactory,并且对 XML 验证方法的所有后续调用都使用相同的工厂。
资源共享:SchemaFactory 创建起来比较繁重,可以配置各种属性。通过使其静态化,我们避免了每次需要验证 XML 时重新创建它。这样可以节省内存和 CPU 周期。
方法 2:如果我们在 validateXmlWithXsd() 方法中创建 SchemaFactory,一旦该方法退出,它将有资格进行垃圾回收,并且该实例占用的内存可能会被释放。因此,这种方法可能不会造成重大的内存问题。
谁能建议方法 1 是否比方法 2 有任何缺点。
答:
SchemaFactory
的文档说它不是线程安全的:
SchemaFactory 类不是线程安全的。换言之,应用程序有责任确保在任何给定时刻最多有一个线程使用 SchemaFactory 对象。
如果可以从多个线程调用,则必须使用同步块或其他锁定机制来确保不会并发使用 。这可能会造成自己的性能瓶颈。validateXmlWithXsd
schemaFactory
评论
schemaFactory
XmlValidator
synchronized (schemaFactory)
这可能取决于您使用的实现方式;既然你没有说,我假设你可能正在使用 Xerces 实现(我没有内部知识)。但是,我猜以下内容适用于所有实现(它当然适用于 Saxon 实现)。SchemaFactory
创建 SchemaFactory 的成本很高;它通常涉及对类路径的搜索。你只想做一次。
创建架构的成本很高。如果重复使用相同的架构来验证不同的文档(这似乎很有可能),则希望将已编译的架构对象保留在缓存中。
在 24x7 全天候运行的应用程序中,将任何内容置于静态状态都是不可取的;使用单实例服务类要好得多。
因此,我建议使用一个拥有 ;让这个类维护一个对象的缓存;并同步相关调用,确保线程安全。SchemaValidationService
SchemaFactory
Schema
评论