分享

annotation深度编程

 zybingliu 2007-08-30

一.为什么需要Annotation

       在annotation之前我们已经广泛使用另外一种元数据xml,为什么需要annotation。Annotation与xml的作为元数据的区别是什么——位置。Annotation写在源代码中,而xml写在外部。
为 什么要这样?如果你开发过EJB,你一定为你的EJB写过xml描述文件。当大量的EJB需要描述时,就出现了所谓的"descriptor hell"。这个也导致了著名的XDoclet的出现。而annotation出现可以避免这种descriptor hell。另外你更改了某个方法为其增加或者减少一个参数,你就对应的修改xml文件,而使用annotation则不必。使用annotation将开 发和部署更方便,提供开发效率。
另外:使用xml的另一个问题是:很多Xml配置太过verbose。相比较EJB和Hibernate 或者Webwork可以明显的发现不同。

 二. 再议Annotation

       在EJB3中,Annotation把开发和部署的工作合在一起。但是在一些企业环境中,开发人员并不控制诸如数据源名等(这些是部署部门和管理部门的工作),这样把数据源名写在xml中将比较好。
Annotation 是本身静态的,一旦添加或者修改annotation都需要重新编译,在运行时读取,这样就丧失了运行时配置的能力。因此Annotations 不会取代xml,它只是提供了另一种途径。并且我相信sun公司将在未来提供一个方式可以在运行期更改metadata。
关于这点TSS上有着很激烈的讨论,很多开发人员提出:利用xml来更改annotation,并希望类似的方式能被采纳为标准规范。比如使用如下格式:

<class >
@Entity
@Table(name="AUCTION_ITEM")
<method sig="getBar()">@Transient</method>
<method sig="doSomething(int, String)">
@Tx(REQUIRES_NEW)
</method>
</class>

      Annotation本身引入另一种类型的接口。在EJB3中确实使程序更加POJO,也消除了一些接口。并且编译后的代码也可以直接移植到另一个并不处 理这些annotations的环境中(感谢VM在加载类时并不检查那些annotations的classes,甚至这些类不在classpath 中)。然而代码也确实增加了另一些接口。这个表现在编译期,如果没有这些annotation classes,是编译不过的。

      另一个问题(还好不算很重要),关于annotation的namespace。在多层应用的系统中,可能会出现同样的全局annotation的 namespace冲突。比如一些公共的annotation,如@Transaction,将会被应用在很多个层次中。尽量让namespace长些, 可以避免这个问题。

三.元数据编程的应用:

  Annotation已经被集成到很多的java规范和标准中,很重要的是它已经被J2EE标准,如EJB3所采用,当然也被许多开源的组件体系如:AspectJ。
Annotation 最重要的应用将是AOP:由于annotation可以天然的表示系统中的另一个横切面,同时Annotation的识别是通过反射得到的,所以 Annotation很自然的应用到基于动态代理的AOP实现。AOP-Alliance也支持metadata handling。AspectJ也发布了基于annotation的新版本。
在实现AOP上,使用annotation也比使用XML有一个优势:如前所述,annotation更像是形容词和副词,这样比较不容易verbose。当然这个是相对的,在实际的实现中更依赖开发人员的努力。
这里,笔者将展示一个不完整也不成熟的基于annotation的AOP例子代码——关于银行卡的例子。

  功能需求:银行卡业务分为转帐,查询余额,查询明细,POS消费等。这其中转帐和POS消费是要收费的(转帐收取的是用户的手续费,而POS消 费收取的是商家的手续费),另外POS消费还可能有积分的(比如笔者的牡丹贷记卡)。消费转帐都要记录明细。但查询余额就不需要记录在明细中。代码如下 (在这个例子没有用动态代理也没有用已有的AOP框架,使代码看起来简单些)

// 银行卡对象
public class Card {
private String account;
//some field method
}

// 事务处理
public @interface Transaction {
}
// 业务接口
public interface BizAction {
void execute(Card card, RunData rundata);
}
// 转帐业务
@Fee(type="user")
@Transaction
@BizLog
public class TransferAction implements BizAction {
public void execute(Card card, RunData rundata) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
// POS消费
@Fee(type="Biz")
@Transaction
@BizLog
@Index
public class POSAction implements BizAction {
public void execute(Card card, RunData rundata) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
// 查询明细
public class QueryDetail implements BizAction {
public void execute(Card card, RunData rundata) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
// 业务操作监视器接口
public interface BizActionMonitor {
void execute(BizAction action, RunData rundata);
}
// 业务操作监视器实现
public class BizActionMonitorImpl implements BizActionMonitor{
public void execute(BizAction action, RunData rundata) {
Annotation[] annotations = action.getClass().getAnnotations();
for(Annotation annotation : annotations){
if (annotation instanceof Fee){ // 计算手续费 }
if (annotation instanceof Index){ //计算积分 }
if (annotation instanceof Transaction){ // 准备事务 }
if (annotation instanceof BizLog){ // 记录明细 }

}
}
}
// 控制器对象
public class controller{
private BizActionMonitor monitor;
public void execute(BizActionUI, rundata){
BizAction action = getAction(BizActionUI);
monitor.execute(action, rundata);
}
}
// 运行时数据
public interface RunData {
// some method
}
// 用户设备(POS机, ATM或者柜台终端)接口
public class BizActionUI {
private RunData rundata;
private Controller controller;
public BizActionUI(RunData rundata, Controller controller){
this.rundata = rundata;
this.controller = controller;
}
public void execute(){ // 某个子类实现 }
public void commit(){
controller.execute(this, rundata);
}
}
public class Main{
private Rundata rundata;
private Controller controller;
public populateUI(command){
BizActionUI ui = getUI(command);
ui.execute();
}
public BizActionUI getUI(command){
//...
BizActionUI ui
if( //....){
ui = new SomeBizActionUI(rundata, controller);
}
return ui;
}
public static main(String[] args){
//...

Main main = new Main();
main.populateUI(command)
//...
}
}

Annotation:
// 手续费
// type= "user", 表示收取用户手续费; type= "Biz", 表示收取商家手续费
public @interface Fee{
String type();
}
// 积分
public @interface Index {
}
// 记录明细
public @interface BizLog {
}

 

结束语:
本文讨论了annotation技术,展示了annotation的class文件格式,并讨论了annotation技术本身的优势和不足,并于现有的xml技术加以比较,展望了annotation技术的应用前景AOP。
限于笔者自身的水平(包括技术水平和写作水平),技术上对annotation的学习比较有限,写作上也感觉好多话无法用文字来表达,因而本文的代码会比较多(大概有一半以上)。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多