为了提高运行效率,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
*/
@Inject
public 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字节码生成部分的源代码,我就不再介绍了(主要是我喜欢用好东西,而不是喜欢研究原理,哈哈~~)。
我先去做点项目的工作了,不做项目没饭吃啊……有点小郁闷