1、 别名的原理

在ZCF框架启动时,会根据插件的依赖顺序扫描所有以UI为后缀并且继承了UIFacade的JAVA类,并根据其中的@Alias注解声明的别名,将别名和JAVA方法的一一对应关系存放到AliasMapping中。通过Zhtml标签或者Server.sendRequest调用UI方法时,都是使用别名,ZCF会通过别名在AliasMapping查找到具体的方法,并通过反射机制执行此方法。


2、 覆盖方式

通过原理可知,如果插件B依赖插件A,而插件B中某个UI方法通过@Alias声明成和插件A中某个UI方法同样的别名,则页面中通过别名调用UI方法时会执行插件B中的方法。需要注意的是,这种覆盖是方法级别的,并且被覆盖的方法在JAVA代码中被调用时依然会执行原方法。

例如插件A中有一个方法声明为

public void A1UI extends UIFacade{
@Alias(alone=true,value="a1")
public void a1(){
    //a1的逻辑
}
}

那么在插件B的任何一个UI类中定义方法

@Alias(alone=true,value="a1")
public void a2(){
    new A1UI().a1();
    //a2扩展的逻辑
}

则在页面中调用别名a1时实际会执行a2方法,但在a2的代码中依然可以调用a1。


3、 和代码织入的不同之处

代码织入能覆盖所有JAVA方法,别名覆盖只能覆盖UI类中通过@Alias声明过的方法。

代码织入覆盖会导致所有调用此方法的地方都执行新的逻辑,而别名覆盖只是在页面调用中才执行新方法,在JAVA类中的调用依然会执行旧方法。

代码织入的侵入式强一些,并且不可调试,因此优先使用别名覆盖。


4、解决什么问题

别名覆盖主要用于项目中需要修改产品中某个UI方法的场合。旧的方式是建一个同名的JAVA包,然后将整个UI类复制或者反编译到此JAVA包中,因为ZCF加载类时WEB-INF/plugin/classes下的类优先jar中的类,从而使项目中的类覆盖了产品中的类。

旧的方式的问题有两个:

一是往往只需要改动UI类中的某个方法,但结果整个类都被覆盖了,维护人员比对改动了哪个方法很困难,会导致维护和升级工作量增加。

二是往往会在新的UI类加入项目特有的逻辑,因此会引用项目插件中的其他JAVA类,但新UI类因为放在和原来的类同名的JAVA包中,所以还是归属于原来的插件,但原来的插件又没有依赖于项目插件,从而导致编译错误

别名覆盖就没有这两个问题:

一、 单个方法覆盖。

二、 新的方法处于项目插件中,没有依赖问题。


5、 实际例子

某个项目需要重写ApplicationUI中的退出和初始化方法,覆盖代码类似于:

package com.zving.pdmi.ui;

import com.chinasofti.oauth2.client.util.CSiUtil;
import com.zving.framework.UIFacade;
import com.zving.framework.annotation.Alias;
import com.zving.framework.annotation.Priv;
import com.zving.framework.core.handler.ZAction;
import com.zving.pdmi.util.PdmiOAuth2Config;

/**
 * Platform ApplicationUI重写
 * 
 */
@Alias("Application")
public class ApplicationUI extends UIFacade {

    /**
     * 加入PDMI登出地址
     */
    @Priv
    public void init() {
        new com.zving.platform.ui.ApplicationUI().init();
        $S("LogoutUrl", PdmiOAuth2Config.getValue("logout_url"));
    }

    /**
     * 加入PDMI登出逻辑
     * 
     * @param za
     */
    @Priv(login = false)
    @Alias(value = "logout", alone = true)
    public void logout(ZAction za) {
        CSiUtil.RemoveSession();
        CSiUtil.clearSession();
        new com.zving.platform.ui.ApplicationUI().logout(za);
    }
}

可以看到:

1、通过new com.zving.platform.ui.ApplicationUI()的方式执行了原有UI类的逻辑。

2、此UI类处于插件所在的com.zving.pdmi包中,可以自由调用pdmi插件中的类。