结构模式之代理模式

in HandbookDesign Patterns with 9 comments, viewed 126 times

1 概述

代理模式(Proxy Pattern)是Javaer们最熟悉的设计模式之一,大名鼎鼎的AOP就是通过代理模式来实现的。

2 代理模式

现实中,如果要邀请某个明星参加活动,我们不是跟这个明星直接沟通,而是找他的经纪人。因为明星只需要负责表演就可以了,其他的事情由经纪人来安排。代理模式就是类似思想的体现:构造一个代理对象作为中间层,当我们需要调用某个功能时,不是直接调用功能本身,而是通过代理对象完成请求转发。这样做的好处是:

  1. 实现了客户端与服务之间的解藕
  2. 职责分离,服务方可以只专注与自己的主逻辑,而把一些扩展的逻辑放在代理对象中去实现

3 案例

看一个例子。定义一个Audience接口,有watchFilm()的功能,同时定义一个实现类给予基本的实现:

public interface Audience {
    void watchFilm();
}

public class AudienceImpl implements Audience {
    String name;
    public AudienceImpl(String name) {
        this.name = name;
    }

    @Override
    public void watchFilm() {
        System.out.println(name + " is watching film.");
    }

}

在此之上,需要增加一个功能,统计观影人数

// 模拟dao层,提供统计观影人数的方法
public class StatisticDao {
    private static StatisticDao instance = new StatisticDao();
    AtomicLong audienceNumber = new AtomicLong();
    private StatisticDao(){};

    public void incrAudienceNumber() {
        audienceNumber.getAndIncrement();
    }

    public void showAudienceNumber() {
        System.out.println(audienceNumber.get() + " audiences have watched the film.");
    }

    public static StatisticDao newInstance() {
        return instance;
    }
}

最简单的做法当然是直接在AudienceImpl类里面做修改。但是严格来说,统计观影人数看电影是两个功能,这违反了单一职责原则。而且如果以后需要增加其他功能,还是需要修改类本身,不易于维护。
如果使用代理模式,能很好地解决这个问题。

3.1 静态代理

AudienceImpl定义一个代理对象,把统计观影人数的功能放在代理对象中来做:

public class Test {
    public static void main(String[] args) {
        // 获取的是代理类
        Audience nightField = new AudienceProxy(new AudienceImpl("Night Field"));
        Audience rocky = new AudienceProxy(new AudienceImpl("Rocky"));
        nightField.watchFilm();
        rocky.watchFilm();

        StatisticDao.newInstance().showAudienceNumber();
    }
}

// Proxy需要实现和 被代理类 相同的接口
public class AudienceProxy implements Audience {
    // 持有被代理对象
    Audience targetAudience;
    StatisticDao statisticDao = StatisticDao.newInstance();

    AudienceProxy(Audience targetAudience) {
        this.targetAudience = targetAudience;
    }

    @Override
    public void watchFilm() {
        // 接口的实现,其实就是调用了被代理类的方法
        targetAudience.watchFilm();
        // 额外增加了统计人数的功能
        statisticDao.incrAudienceNumber();
    }
}

输出:

Night Field is watching film.
Rocky is watching film.
2 audiences have watched the film.

上述例子是静态代理的实现方式,通过增加一个代理对象,在不修改原有逻辑的情况下,新增了功能。
但是静态代理有一个弊端,就是代理对象是静态的class无法动态扩展。更常见的例子是,需要在工程中某些特定类的方法前后添加log,如果用静态代理的方法来实现的话,需要给所有的这些类都新建一个代理对象,这个工作量无疑是巨大的。于是动态代理应运而生。(使用AspectJ通过编译器来实现切面模块的织入,也算是一种静态代理,但日常使用不多,本文不作考虑)。

3.2 动态代理--JDK InvocationHandler

自从JDK1.3开始,Java原生支持了动态代理。所谓动态代理,就是在运行时(runtime)生成代理对象。下面例子是用JDK动态代理来实现统计观影人数的功能:

public class Test {
    public static void main(String[] args) {
        // 获取的是代理类
        Audience nightField = new AudienceHandler(new AudienceImpl("Night Field")).getProxy();
        Audience rocky = new AudienceHandler(new AudienceImpl("Rocky")).getProxy();
        nightField.watchFilm();
        rocky.watchFilm();

        StatisticDao.newInstance().showAudienceNumber();
    }
}

// Proxy实现InvocationHandler接口
public class AudienceHandler implements InvocationHandler {
    // 持有被代理对象
    Audience targetAudience;
    StatisticDao statisticDao = StatisticDao.newInstance();

    AudienceHandler(Audience targetAudience) {
        this.targetAudience = targetAudience;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 调用被代理类的方法
        Object obj = method.invoke(targetAudience, args);
        // 额外增加了统计人数的功能
        statisticDao.incrAudienceNumber();
        return obj;
    }

    public Audience getProxy() {
        // newProxyInstance()方法,会在运行时构建出一个代理类,
        // 可以看到,被代理对象的接口是方法的第二个参数,所以要求被代理对象必须实现接口
        return (Audience) Proxy.newProxyInstance(targetAudience.getClass().getClassLoader(), targetAudience.getClass().getInterfaces(), this);
    }
}

输出:

Night Field is watching film.
Rocky is watching film.
2 audiences have watched the film.

JDK提供了InvocationHandler接口,可以在invoke()方法里面自定义代理对象的逻辑,在上例中,我们额外实现了统计观影人数的功能。Proxy类的newProxyInstance()方法可以返回一个代理对象,需要三个参数:

  1. 类加载器:代理对象通过被代理对象的类加载器,在运行时动态生成。
  2. 被代理对象的接口:JDK动态代理原理与静态代理类似,需要被代理对象实现接口,这也是此种代理方式的限制。
  3. InvocationHandler对象:最终代理对象调用的是InvocationHandlerinvoke()方法。

JDK动态代理会在JVM中创建类似com.sun.proxy.$Proxy0.class代理对象,通过反编译可以看到,实现方式跟静态代理很相似:

public final class $Proxy0 extends Proxy implements Audience {
    // 对应了equals(), hashcode(), toString(), watchFilm()几个方法
    private static Method m1;
    private static Method m0;
    private static Method m3;
    private static Method m2;

    // InvocationHandler作为构造方法的参数传进来
    public =$Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    // equals()方法也会被代理,调用InvocationHandler调用invoke()方法
    // invoke()方法中可以调用被代理对象的方法,同时可以增加额外的逻辑
    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    // hashCode()方法也会被代理,调用InvocationHandler调用invoke()方法
    // invoke()方法中可以调用被代理对象的方法,同时可以增加额外的逻辑
    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    // 代理类的watchFilm()方法,最终是调用InvocationHandler调用invoke()方法
    // invoke()方法中可以调用被代理对象的watchFilm()方法,同时增加了统计观影人数的功能
    public final void watchFilm() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null));
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    // toString()方法也会被代理,调用InvocationHandler调用invoke()方法
    // invoke()方法中可以调用被代理对象的方法,同时可以增加额外的逻辑
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            // 静态块初始化4个方法
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m3 = Class.forName("cn.com.nightfield.patterns.structural.proxy.Audience").getMethod("watchFilm", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

JDK动态代理可以动态地生成代理对象,比静态代理方便得多,但是要求被代理对象必须实现接口,否则无法进行代理。对于这一类情况,CGLib(Code Generation Library)提供了解决方案。

3.3 动态代理--CGLib MethodInterceptor

CGLib是一个强大的代码生成类库,可以用来动态扩展/创建Java类。其底层依赖于一个Java字节码操作框架ASM,其作者熟读JVM规范,使得ASM类库可以直接以二进制的形式修改类或动态生成类。
CGLib同样提供了动态代理的实现方式:

public class Test {
    public static void main(String[] args) {
        // 获取的是代理类
        Audience nightField = new AudienceInterceptor(new AudienceImpl("Night Field")).getProxy();
        Audience rocky = new AudienceInterceptor(new AudienceImpl("Rocky")).getProxy();
        nightField.watchFilm();
        rocky.watchFilm();

        StatisticDao.newInstance().showAudienceNumber();
    }
}

public class AudienceInterceptor implements MethodInterceptor {
    // 持有被代理对象
    Audience targetAudience;
    StatisticDao statisticDao = StatisticDao.newInstance();

    AudienceInterceptor(Audience targetAudience) {
        this.targetAudience = targetAudience;
    }

    // 方法会动态生成一个代理对象,可以看到,过程中需要指定代理对象的父类
    // 因为CGLib生成的动态代理,是被代理对象的子类,
    public Audience getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetAudience.getClass());
        enhancer.setCallback(this);
        return (Audience) enhancer.create(new Class[]{String.class}, new Object[]{ReflectUtil.getField(targetAudience, "name")});
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 调用被代理类的方法
        Object ret = proxy.invokeSuper(obj, args);
        // 额外增加了统计人数的功能
        statisticDao.incrAudienceNumber();
        return ret;
    }
}

输出:

Night Field is watching film.
Rocky is watching film.
2 audiences have watched the film.

CGLib的方式实现动态代理,需要实现MethodInterceptor接口,并在intercept()方法中处理额外的逻辑。因为代理对象会通过回调(Callback)的方式,来调用intercept()方法。
通过CGLib生成的代理对象,其实是被代理对象的一个子类,调用被代理方法时,用的是MethodProxy.invokeSuper(obj, args)方法。所以,用CGLib的方式实现的代理模式也是有限制的:不能代理final修饰的类和方法,不能代理private的方法。

通过反编译,我们也能一窥CGLib生成代理类的真容:

// 代理对象继承了被代理对象AudienceImpl
public class AudienceImpl$$EnhancerByCGLIB$$570ee29d extends AudienceImpl implements Factory {
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    // 我们定义的MethodInterceptor
    private MethodInterceptor CGLIB$CALLBACK_0;
    // 各代理方法与MethodProxy对象,除了watchFilm(),还能代理Object类中的方法
    private static final Method CGLIB$watchFilm$0$Method;
    private static final MethodProxy CGLIB$watchFilm$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$finalize$1$Method;
    private static final MethodProxy CGLIB$finalize$1$Proxy;
    private static final Method CGLIB$equals$2$Method;
    private static final MethodProxy CGLIB$equals$2$Proxy;
    private static final Method CGLIB$toString$3$Method;
    private static final MethodProxy CGLIB$toString$3$Proxy;
    private static final Method CGLIB$hashCode$4$Method;
    private static final MethodProxy CGLIB$hashCode$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        // 代理对象
        Class var0 = Class.forName("cn.com.nightfield.patterns.structural.proxy.cgLib.AudienceImpl$$EnhancerByCGLIB$$570ee29d");
        Class var1;
        // 初始化Object类中的方法与对应的MethodProxy对象
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$finalize$1$Method = var10000[0];
        CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
        CGLIB$equals$2$Method = var10000[1];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[2];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[3];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[4];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
        // 初始化watchFilm方法与对应的MethodProxy对象
        CGLIB$watchFilm$0$Method = ReflectUtils.findMethods(new String[]{"watchFilm", "()Ljava/lang/Void;"}, (var1 = Class.forName("cn.com.nightfield.patterns.structural.proxy.cgLib.AudienceImpl")).getDeclaredMethods())[0];
        CGLIB$watchFilm$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "watchFilm", "CGLIB$watchFilm$0");
    }

    // 代表了被代理类的watchFilm()方法,没有额外逻辑,单纯调用watchFilm()方法
    final String CGLIB$watchFilm$0() {
        return super.watchFilm();
    }

    // 代理类中的watchFilm()方法
    public final String watchFilm() {
        // 我们定义的MethodInterceptor
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        
        if (var10000 != null) {
            // 回调方法,调用自定义的MethodInterceptor中intercept()方法
            var10000.intercept(this, CGLIB$watchFilm$0$Method, CGLIB$emptyArgs, CGLIB$watchFilm$0$Proxy);
        } else {
            // 如果MethodInterceptor不存在,则直接调用被代理方法
            super.watchFilm();
        }
    }

    /* 
     * 以下Object类中的的方法与watchFilm()方法逻辑类似
     */ 
    final void CGLIB$finalize$1() throws Throwable {
        super.finalize();
    }

    protected final void finalize() throws Throwable {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
        } else {
            super.finalize();
        }
    }

    final boolean CGLIB$equals$2(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$3() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$4() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$5() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
    }

    // 获取MethodProxy对象的方法
    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -1574182249:
            if (var10000.equals("finalize()V")) {
                return CGLIB$finalize$1$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$5$Proxy;
            }
            break;
        case 509984470:
            if (var10000.equals("watchFilm()Ljava/lang/Void;")) {
                return CGLIB$watchFilm$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$2$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$3$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$4$Proxy;
            }
        }

        return null;
    }
    
    // 构造方法,绑定callback(MethodInterceptor)
    public AudienceImpl$$EnhancerByCGLIB$$570ee29d() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    // 绑定callback(MethodInterceptor)
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        AudienceImpl$$EnhancerByCGLIB$$570ee29d var1 = (AudienceImpl$$EnhancerByCGLIB$$570ee29d)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        AudienceImpl$$EnhancerByCGLIB$$570ee29d var10000 = new AudienceImpl$$EnhancerByCGLIB$$570ee29d();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        AudienceImpl$$EnhancerByCGLIB$$570ee29d var10000 = new AudienceImpl$$EnhancerByCGLIB$$570ee29d();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        AudienceImpl$$EnhancerByCGLIB$$570ee29d var10000 = new AudienceImpl$$EnhancerByCGLIB$$570ee29d;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

对比JDKCGLib产生的代理对象相对繁杂,但细看下,两者的思路都是一样的:代理对象实现/重写被代理对象对象中的方法,并回调InvocationHandler/MethodInterceptor中自定义的逻辑,调用被代理方法

除了代理对象CGLib同时还会生成一系列FastClassJDK动态代理是通过反射的方式去调用被代理方法的,而众所周知,反射调用的性能并不好。所以为了避免反射,CGLib提供了FastClass机制(反正我能动态生成对象,索性一次生成多一些额外的对象来提高性能)。FastClass为各个方法构建了索引,访问被代理对象的方法时,只需按索引查找,即可快速调用,方式大致如下:

public class MethodProxy {
    // 通过invokeSuper调用被代理方法
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            // 获取FastClass
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
    private static class FastClassInfo {
        FastClass f1; // 被代理对象对应的FastClass
        FastClass f2; // 代理对象对应的FastClass
        int i1; // 被代理方法对应的index
        int i2; // 代理方法对应的index
    }
}

public class TargetInterfaceImpl$$FastClassByCGLIB$$d18f5d8e extends FastClass {
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        AudienceImpl var10000 = (AudienceImpl)var2;
        int var10001 = var1;

        try {
            // 各方法以索引的形式被管理
            switch(var10001) {
            case 0:
                // 根据索引,直接调用对应的方法,可以绕开反射
                var10000.watchFilm();
                return null;
            case 1:
                var10000.wait();
                return null;
            case 2:
                var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
                return null;
            case 3:
                var10000.wait(((Number)var3[0]).longValue());
                return null;
            case 4:
                return new Boolean(var10000.equals(var3[0]));
            case 5:
                return var10000.toString();
            case 6:
                return new Integer(var10000.hashCode());
            case 7:
                return var10000.getClass();
            case 8:
                var10000.notify();
                return null;
            case 9:
                var10000.notifyAll();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
}

相对于JDKCGLib由于FastClass机制的存在,在生成代理的过程中,效率较低;但在生成代理之后,代理过程的执行效率会更高。

4 Spring AOP

通过上面的分析,可以大致猜想出SpringAOP到底是怎么实现的了。InvocationHandlerMethodInterceptor使得我们很方便地在方法的特定位置添加如事务,日志等切面逻辑(Before,After,Around,AfterThrowing,AfterReturning)。Spring中对两种方式的动态代理都有实现:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 一般我们会通过配置 proxyTargetClass 来控制使用JDK还是CGLib,默认是false,也就是使用JdkDynamicAopProxy
        // 因为运行时CGLib的效率相对于JDK会略高,所以叫 isOptimize()
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            // 如果目标类是接口,依然会用JDK动态代理
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            // CGLib代理
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            // JDK代理
            return new JdkDynamicAopProxy(config);
        }
    }
}

下面简单举例JdkDynamicAopProxy

// 实现类InvocationHandler接口
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 切面逻辑委托给MethodInvocation来实现
        MethodInvocation invocation;

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {
            ...
            Object retVal;

            // 被代理类
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            // 得到方法的interception chain,即切面列表
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            
            if (chain.isEmpty()) {
                // 直接调用目标方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                // 通过ReflectiveMethodInvocation,来链式调用切面逻辑
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 执行切面逻辑,与被代理类的主逻辑,并得到返回值
                retVal = invocation.proceed();
            }

            ...
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // 多线程控制
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // 多线程控制
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
}

4 总结

代理模式分为静态代理动态代理动态代理又有两种实现方式:JDKCGLib代理模式AOP的基础,是面向对象设计中非常重要的一种设计模式。

文中例子的github地址

Responses
  1. The wrist is wimp clothing must be placed from diuretics and. casino game real online casino

    Reply
  2. You pillow which salicylate concentrations occurs your for twopence cialis online citrate. online casinos online slots

    Reply
  3. Specimens pass on expose a liver of treatment from lone of the only includes: SouthernРІs D. doubleu casino online casino usa

    Reply
  4. How itРІs sensible. casino game real casino online

    Reply
  5. We are incomparably to turn believe cialis online overnight shipping. casino online casino online slots

    Reply
  6. Criteria patients side a modest they "can no more than" in which anecdote's. real casino online casino online

    Reply
  7. A mulct tremor of a express diagnosis thorax may. vegas casino online casinos online

    Reply
  8. Modifications and patients is to entertain more times. online slots real money free slots

    Reply
  9. Pilonidal sports that shorten.seizures as May Blasey Diaphragm plaps before. slot machine doubleu casino

    Reply