动态管理 XMLBeans 应用程序中的 XML 模式变体,使用动态类加载克服 XMLBeans 中的处理限制

 

Apache XMLBeans 是一种开源的、与 XML 和 Java™ 绑定的工具,可用来从 XML 模式生成 Java 类和接口。使用生成的 beans,就可以解析或生成遵循模式的 XML 文档。因此,这种绑定会紧密地将生成的 Java 类和 XML 模式耦合在一起。在对 XML 模式执行或大或小的修改时,将重新生成 bean 并使用与修改后的 XML 模式对应的新 bean。至少,它正设法实现这一点。不幸的是,应用程序有时需要支持多个模式版本。例如,如果将 XML 用作数据交换标准,应用程序必须提供向前和向后兼容性,以支持较新或较旧的版本标准。

环境设置

考虑一个雇员数据管理应用程序,其中应用程序使用 XML 文件的形式保存雇员信息,并使用 Apache XMLBeans 进行处理。雇员数据一直由 XSD 定义,如清单 1 所示。模式使用 XMLBeans 模式编译器编译。应用程序然后使用生成的 Java 类和接口处理传入的 XML 文档,这个文档遵循 XSD,名称空间为 com.ibm.sample.employee:1


清单 1. 雇员 XML 模式的第一个版本

清单 2 展示了处理雇员 XML 的应用程序,清单 3 展示了使用它的客户机应用程序:


清单 2. XMLBeans 应用程序

清单 3. 客户机

				
    EmployeeApplication app = new EmployeeApplication();
    app.parseXML(xmlFilePath);

模式变更简介

现在假设模式被更改,为旧模式生成的 Java bean 再也不能使用新模式处理 XML。清单 4 展示了修改后的模式,其中添加了一些新元素,并将名称空间改为 com.ibm.sample.employee:2,表示这是第二个版本。


清单 4. 雇员 XML 模式的第二个版本

要确保向前兼容性,您不希望修改客户机应用程序。但是,输入 XML 的数据源已升级到新的模式,因此应用程序必须能够处理传入的具有任何名称空间的雇员 XML 数据。但是 XMLBeans 无法管理冲突的模式,您应该如何处理这个问题?

克服处理限制

常用缩写词
  • JRE:Java 运行时环境(Java Runtime Environment)
  • JVM:Java 虚拟机(Java Virtual Machine)
  • SAX:Simple API For XML
  • URL:统一资源定位符(Uniform Resource Locator)
  • XML:可扩展标记语言
  • XSD:XML 模式定义

要想应用程序能够处理新的 XML 模式,您将需要生成一组与新模式对应的新 Java bean。因为不希望修改应用程序,因此需要确保 Apache XMLBeans 生成的新 Java bean 具有和旧 bean 相同的包名。这样,应用程序不需要修改代码就可以使用这些 bean。将 com.ibm.sample.employee:1com.ibm.sample.employee:2 名称空间映射到一个单个 Java 包,比如 com.ibm.sample.employee(映射不属于本文讨论范围;更多信息请参阅 参考资料)。

将不同 Java bean 集合对应到不同模式后,您只需根据传入的 XML 加载合适的 bean。可以使用动态类加载技术确保加载正确的 bean 集合。以下小节展示如何使用代理模式和 Java 类加载来加载与每个模式对应的多个 XMLBeans 版本。

Java 类加载

在 Java 编程中,类加载器是一级对象,并且具有自己的名称空间。类加载器实例加载的类由加载器的名称空间和类名惟一标识。例如,假设您有一个名为 MyClassLoader 的类加载器。如果这个类加载器的一个实例 myLoaderA 加载了类 Foo,并且另一个实例 myLoaderB 加载了相同的类 Foo,那么 JVM 将类 Foo 视为两个不同的类并执行两次加载(参见图 1)。


图 1. Java 类加载

 

Java 类加载使用一个委托模型来加载类。每个类加载器有一个父类加载器,在尝试加载类本身时,先将类搜索和类加载委托给它的父加载器,即父加载器优先(parent-first)委托。当类加载器存在一个层次结构时,根类加载器(即引导类加载器)将首先尝试加载类。如果不行的话,再由系统类加载器尝试加载,等等(更多有关 Java 类加载的信息,请参阅 参考资料)。

要处理两种不同的模式版本,可以创建不同的类加载器实例,并且让每个实例加载与 XML 模式对应的应用程序和 Java bean 版本。

代理

接着,将创建一个代理,使用公共接口作为原始的应用程序或 bean。代理将为每个 XML 模式版本创建一个类实例。类加载器的父类加载器将是当前线程上下文的类加载器。根据正在处理的 XML 模式,这个代理使用合适的类加载器实例加载与每个 XSD 对应的 Java bean 和应用程序本身。多次加载应用程序是因为当 JVM 尝试加载应用程序使用的所有类时,它将在相同的名称空间中查找。如果没有找到的话,它将抛出 ClassNotFound 异常。图 2 展示了代理的工作方式:


图 2. 代理动态加载 XMLBeans

 

代理可以使用接收的 XML 的名称空间确定要加载哪个 XMLBeans,或者 XML 可以使用一个元素表示 XSD 的版本。代理然后可以使用一个简单 SAX 解析器检索信息。

处理多个模式版本的样例应用程序

重新看一下雇员数据管理应用程序。清单 5 展示了代理代码:
清单 5. 代理

 

在这个清单中,名称空间为 com.ibm.sample.employee:1 的 XSD 的 Java beans 被归档到名为 employee1.jar 的 JAR 文件中;而名称空间为 com.ibm.sample.employee:2 的 XSD 的 Java bean 被归档到名为 employee2.jar 的 JAR 文件中。在运行时,JAR 文件或是应用程序本身的类文件都不会包含在类路径中,因为它们将由 URLClassLoader 的实例从代理中加载。如果这些类在类路径中可用,URLClassLoader 实例的父加载器(即系统类加载器)将加载它们。同样,不能加载这些 JAR 文件的多个版本,因为类都位于系统类加载器名称空间中。

代理决定输入 XML 使用哪个 XML 模式版本;然后创建一个 URLClassLoader 实例,并将相应 JAR 文件的 URL 添加到 URLClassLoader 的类路径中。代理包含了类加载器的相应实例之后,它将使用 Java 反射来调用原始应用程序(或 bean)的相应方法。这里,我们使用反射的原因是因为我们已经使用非系统类加载器加载了应用程序。

现在雇员数据管理应用程序可以处理遵守任何 XML 模式的雇员数据。清单 6 展示了将使用代理调用应用程序的代码:


清单 6. 修改后的客户机应用程序

				
// Create an instance of the proxy instead of the employee application
EmployeeApplicationProxy app = new EmployeeApplicationProxy();
    app.parseXML(xmlFilePath);

在这个示例中,应用程序保持不变。但是在某些情况下,可能需要修改应用程序,因为需要使用某些新的处理流程来处理遵循新模式(比如地址)的 XML 数据。因此,需要管理两个应用程序代码集。在这种情况下,您可以加载不同的应用程序版本(或一部分)和特定 XSD 版本的 Java bean。这种方法的优点是您可以最小化应用程序的更改,并在频繁修改模式的情况下轻松地管理应用程序。同样,可以轻松地添加或删除模式版本支持。

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值