结构模式之代理模式

原创
04/16 22:59
阅读数 57

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](https://my.oschina.net/u/1162528)
    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](https://my.oschina.net/u/1162528)
    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](https://my.oschina.net/u/1162528)
    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](https://my.oschina.net/u/1162528)
    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](https://my.oschina.net/u/1162528)
	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地址

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部