nkadun 发表于 2013-1-27 04:59:46

3.objot示例之代码织入

为了提高运行效率,objot采用了bytecode(字节码)生成的方式,即在原有的服务类的方法中插入一些代码而形成一个子类,但在外界看起来还是原有的类。下面我们来看一下Weaver的强大功能。
还是以第二篇的例子,假设DoUser的operate方法的调用需要有权限控制,而像这种控制在很多地方都可能会有,我们不会手动在每个方法添加大量权限判断的代码(与业务无关的代码),因为我们有Weaver,它会帮我们处理好这些事情。
//DoUser.java文件
package objot.sample.service;import objot.container.Inject;/*** 用户服务* @author adun*/public class DoUser extends Do {/*** 为了方便演示,我们假设调用者的权限代码为1*/public int permit = 1;/*** 被注入的DoBiz*/@Injectpublic DoBiz db;/*** 具有权限0的调用者可以调用本方法*/@Sign(permit = 0)public void operate() {   db.doSth();}}

由于DoBiz没有任何变化,我们就不在这里再贴同样的代码了,请参见第二篇。我们主要再来看一下@Sign(意为“登录信息”)的定义:
//Sign.java文件
package objot.sample.service;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import objot.aspect.Aspect;/*** 登录信息标记* @author adun*/@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Sign {/*** 权限*/int permit();/*** 对于权限的处理逻辑类,代码将会被织入到DoUser.operate方法中* @author 司马春雪**/public static final class As extends Aspect {   @Override   protected void aspect() throws Throwable {    //得到被@Sign标志的方法所属的类    DoUser du = Target.thiz();    //得到标志的实例    Sign sign = Target.data();    //判断权限是否相等    if (du.permit != sign.permit()) {   throw new Exception("您没有这个权限");    }    //调用方法,即调用DoUser.operate    Target.invoke();   }}}

这样一来,我们的定义工作都做完了,接下来我们要“织布”了^_^!
//Sample.java文件
package objot.sample;import java.lang.reflect.Method;import objot.aspect.Aspect;import objot.aspect.Weaver;import objot.container.Bind;import objot.container.Container;import objot.container.Factory;import objot.sample.service.Do;import objot.sample.service.DoUser;import objot.sample.service.Sign;import objot.util.Class2;import objot.util.Mod2;/*** 示例主程序* @author adun*/public class Sample {public static void main(String[] args) throws Exception {   //新建一个织入器,并将Sign.As织入   final Weaver w = new Weaver(Sign.As.class) {    @Override    protected Object forWeave(Class<? extends Aspect> a, Method m) throws Exception {   //判断aspect类是否为Sign.As并且织入目标类的方法被Sign标记过   if (a == Sign.As.class && m.getAnnotation(Sign.class) != null) {      return m.getAnnotation(Sign.class);   }   return this;    }   };   //新建容器工厂,为了将服务类在织入后再放入容器中,我们需要对Factory进行自定义   Factory factory = new Factory() {    {   for(Class<?> c : Class2.packageClasses(Do.class)) {      //只绑定继承于Do(或Do本身)并且非抽象类到容器中      if (!Mod2.match(c, Mod2.ABSTRACT) && Do.class.isAssignableFrom(c)) {       bind(c);      }   }    }    /**    * 绑定前的预处理,即我们要对服务类织入代码后再绑定到容器    */    @Override    protected Object forBind(Class<?> c, Bind b) throws Exception {   //判断要绑定的类是否是我们通过编译器引入的(即不需要再进行织入操作)   //否则要对c进行织入操作   return c.isSynthetic() ? b : b.cla(w.weave(c));    }   };   //生成容器c,c的父容器为null   Container c = factory.create(null);   //开始从容器中得到一个DoUser的实例   DoUser du = c.get(DoUser.class);   //执行   du.operate();}}
执行结果:
Exception in thread "main" java.lang.Exception: 您没有这个权限
at objot.sample.service.Sign$As$$23105029$objot$sample$service$DoUser.operate(Sign.java:35)
at objot.sample.Sample.main(Sample.java:58)

因为du的permit为1,而要执行operate需要permit为0,那么将DoUser.permit改为0再试一下,就会得到如下结果:
开始操作

是不是有点好玩呢?个人认为这里面强大的且难于理解的是字节码的生成,即通过对类进行“暴力”修改而得到的新的子类,会极大提高运行效率(相对于反射机制)。有兴趣的朋友可以看一下objot字节码生成部分的源代码,我就不再介绍了(主要是我喜欢用好东西,而不是喜欢研究原理,哈哈~~)。
我先去做点项目的工作了,不做项目没饭吃啊……有点小郁闷http://www.agoit.com/images/smiles/icon_sad.gif
页: [1]
查看完整版本: 3.objot示例之代码织入