Java AOP实现

1. 业务代码

public interface CellPhone {
    void description(Integer sequence);
    void setVersion(String version);
}

public class IOS implements CellPhone {
    private String version;

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public IOS(){}

    public void description(Integer sequence) {
        System.out.println("{sequence="+sequence+",version="+this.version+"}");
    }
}

public class Android implements CellPhone {
    private String version;

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public Android(){}

    public void description(Integer sequence) {
        System.out.println("{sequence="+sequence+",version="+this.version+"}");
    }
}

1. 使用动态代理

实现代码:

public class CellPhoneProxy implements InvocationHandler{
    private Object obj;

    private CellPhoneProxy(Object obj){
        this.obj = obj;
    }

    @SuppressWarnings("unchecked")
    public static<T> T getProxyInstance(Class<T> clazz){
        Object target = null;
        try {
            target = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (T)Proxy.newProxyInstance(clazz.getClassLoader(),
                                    clazz.getInterfaces(), new CellPhoneProxy(target));
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if(method.getName().equals("description"))
            System.out.print("call "+obj.getClass().getSimpleName()+"."+method.getName()+"():");
        else
            System.out.println("call "+obj.getClass().getSimpleName()+"."+method.getName()+"()");
        Object result = method.invoke(obj, args);
        return result;
    }
}

测试代码:

public void test(){
    /* Android */
    CellPhone bean = CellPhoneProxy.getProxyInstance(Android.class);
    bean.description(1);
    bean.setVersion("4.2.0");
    bean.description(2);

    /* IOS */
    bean = CellPhoneProxy.getProxyInstance(IOS.class);
    bean.description(1);
    bean.setVersion("7.2");
    bean.description(2);
}

2. 使用cglib

实现代码:

public class CellPhoneInterceptor implements MethodInterceptor{
    public Object intercept(Object target, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {    
        if(method.getName().equals("description"))
            System.out.print("call "+target.getClass().getSimpleName()+"."+method.getName()+"():");
        else
            System.out.println("call "+target.getClass().getSimpleName()+"."+method.getName()+"()"); 
        Object rev = proxy.invokeSuper(target, args);  
        return rev;   
    }
}

测试代码:

public void test(){
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Android.class);
       enhancer.setCallback(new CellPhoneInterceptor());
       Android android = (Android)enhancer.create();
    android.description(1);
    android.setVersion("4.2.0");
    android.description(2);

    enhancer = new Enhancer();
    enhancer.setSuperclass(IOS.class);
       enhancer.setCallback(new CellPhoneInterceptor());
       IOS ios = (IOS)enhancer.create();
       ios.description(1);
       ios.setVersion("7.2");
       ios.description(2);
}

3. 使用javassit

实现代码:

public class CellPhoneTranslator implements Translator{

    /**
     * Class装载入JVM之前进行代码织入
     * 
     */
    public void onLoad(ClassPool pool, String className) throws NotFoundException,
            CannotCompileException {
        CtClass cc = pool.get(className);
        if(className.equals("edu.njupt.afly.aop.testclass.Android")){
            //description方法织入
            CtMethod description = cc.getDeclaredMethod("description");
            description.insertBefore("{System.out.println(\"call Android description\");}");
            //setVersion方法织入
            CtMethod setVersion = cc.getDeclaredMethod("description");
            setVersion.insertBefore("{System.out.println(\"call Android setVersion\");}");
        }else if(className.equals("edu.njupt.afly.aop.testclass.IOS")){
            //description方法织入
            CtMethod description = cc.getDeclaredMethod("description");
            description.insertBefore("{System.out.println(\"call IOS description\");}");
            //setVersion方法织入
            CtMethod setVersion = cc.getDeclaredMethod("description");
            setVersion.insertBefore("{System.out.println(\"call IOS setVersion\");}");
        }
    }

    public void start(ClassPool pool) throws NotFoundException,
            CannotCompileException {

    }

    public static void main(String[] args) {   
        final CellPhone android = new Android();
        final CellPhone mac = new IOS();
        android.setVersion("4.2.0");
        android.description(1);
        mac.setVersion("7.2");
        mac.description(2);
    }  
}

测试代码:

public void test(){
    //获取存放CtClass的容器ClassPool   
    ClassPool cp = ClassPool.getDefault();   
    //创建一个类加载器   
    Loader cl = new Loader();   
    //增加一个转换器   
    try {
        cl.addTranslator(cp, new CellPhoneTranslator());
    } catch (NotFoundException e) {
        e.printStackTrace();
    } catch (CannotCompileException e) {
        e.printStackTrace();
    }
    try {
        cl.run("edu.njupt.afly.aop.javassist.CellPhoneTranslator", null);
    } catch (Throwable e) {
        e.printStackTrace();
    }
}

4. 总结

  • 实现方式:动态代理使用java的反射机制,通过在运行期生成接口的代理子类来实现;cglib是利用字节码技术,在运行期实现一个目标类的子类,然后在子类中通过拦截的方式织入横切逻辑,其实现依赖于ASM;javassist也是利用字节码技术,但是javassit是在类加载阶段将横切逻辑织入进方法体内,所以其效率更好。
  • 特点:发射和cglib是在运行期实现横切逻辑的织入,所以其效率较低,但是胜在可以获得方法调用的参数和返回值,功能更强大;而javassist因为是在类加载阶段织入横切逻辑,所以其效率相较于前两种方式较高,但是无法获得调用参数和返回值,有局限性。

以上是个人理解,欢迎大家批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值