Java配置管理:注解与XML文件的权衡

在Java开发中,配置管理是一个不可或缺的环节。开发者经常面临一个选择:是将配置信息放在注解中,还是XML文件中。这两种方法各有利弊,注解将配置与Java源代码紧密关联,但修改注解需要Java知识并重新编译;而XML文件易于修改,并且可以在运行时重新读取(有时甚至不需要重启应用程序),但它们非常冗长,编辑时容易出错。

通常,最佳做法是结合使用这两种方法。例如,遵循的一条经验法则是:“任何指向Java元素(包、类、方法)的配置参数应该在注解中指定”(例如@Test或@Transaction),而“任何适用于整个应用程序的配置参数可能属于XML文件”(例如输出日志文件的名称或目标Web服务器)。

最近,一种结合这两种技术的方法也受到了关注:能够使用XML文件覆盖Java注解。还没有遇到可以宣称是事实上的标准的实现,目前怀疑这种方法不太可能流行起来,因为它似乎结合了两种方法的最差方面。

代码示例

考虑以下简单的代码: public class MyTest { @Test(invocationCount = 10) public void verify() { // ... } } 这段代码指示TestNG调用verify()测试方法十次。

如果要在运行时覆盖这个值,发现自己不得不编写相当复杂的XML代码来精确指定想要覆盖的注解。它可能看起来像这样: <override-annotation> <package name="org.foo.tests"> <class name="MyClass"> <method name="verify"> <annotation name="org.testng.Test"> <attribute name="invocationCount" value="15"/> </annotation> </method> </class> </package> </override-annotation>

当然,可能想要找到一种方法来捕获覆盖(注解/属性部分),以便可以在XML文件的其他位置重复使用它,以防想让这个覆盖应用于不仅仅是一个方法。这可能通过在XML文件顶部定义一个“override-ref”来实现,然后可以在XML文件中多次使用它(就像ant的classpath-ref一样)。

这已经是很多工作了(而且很难阅读),但它也非常脆弱,因为如果决定重命名类或方法名,它很可能会中断(IDE开始将重构扩展到非Java文件,但还没有完全实现)。

TestNG的解决方案

由于这些缺点,一直在与TestNG一起研究一种稍微不同的方法,让可以在Java中指定这个运行时覆盖。这并不是万能的,也存在上述表达的一些妥协,但如果能接受修改覆盖时需要重新编译的想法(但不是要覆盖的注解代码,所以这已经是进步了),实现起来其实相当简单。

TestNG引入了以下接口: public interface IAnnotationTransformer { void transform(ITest annotation, Class testClass, Constructor testConstructor, Method testMethod); }

使用方式如下: public class MyTransformer implements IAnnotationTransformer { public void transform(ITest annotation, Class testClass, Constructor testConstructor, Method testMethod) { if ("verify".equals(testMethod.getName())) { annotation.setInvocationCount(15); } } }

这种方法的想法是,每当TestNG解析@Test注解时,它会在使用它之前通过注解转换器运行它。

方法的三个额外参数让知道这个注解在哪里找到的(在类、构造函数或方法上)。这三个参数中只有一个是非空的。

注意transform()方法的参数是一个ITest。这是因为TestNG支持标准和JavaDoc注解,所以ITest是一个简单的代表@Test(JDK)或@testng.test(JavaDoc)注解的门面对象。在更一般的框架中,参数可能直接是注解的类型,尽管仍然有一些问题需要解决(见下一点)。

这种方法需要对注解有写入访问权限,这在当前的JDK实现中是不可能的。可以通过使用门面来绕过这个限制,这个门面可能作为一个动态代理生成。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485