设计模式——代理模式实现与原理分析

本文详细介绍了代理模式的概念、分类及其应用场景,包括静态代理和动态代理的实现方式,特别讲解了JDK动态代理的工作原理和CGLib实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式介绍

  代理模式也称为委托模式,也是极为重要的设计模式之一。代理在我们日常生活中其实很常见,对于程序员来说最常接触的莫过于使用代理上网,连接上代理服务器地址,就可以轻松畅游全世界的网络;让同事帮忙带饭也是一种代理方式。代理模式实质就是委托。

定义

  为其它对象提供一种代理以控制对这个对象的访问。

使用场景

  当无法或不想直接访问某个属性或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。

UML类图

代理模式

角色介绍

  • Subject:抽象主题类
    该类的主要职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口。
  • RealSubject:真实主题类
    该类也称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体业务逻辑方法,而客户端则通过代理类间接地调用真实主题类中定义的方法。
  • ProxySubject:代理类
    该类也称为委托类或代理类,该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行,以此起到代理的作用。
  • Client 客户类
    使用代理类的类型。

简单实现

  下面以一个代购的生活案例来展示代理模式的实现,生活中代购的方式非常普遍,做代购的人帮助顾客购买那些顾客自己不容易买的商品并收取一定的佣金,这是一个典型的代理模式的例子。

购物接口IShop,定义购物行为.

/**
 * 购物接口
 */
public interface IShop {
    /**
     * 买东西
     */
    void buy();
}

Customer类实现了购物接口。

/**
 * 顾客类实现了购物接口
 */
public class Customer implements IShop {
    public void buy() {
        System.out.println("买到了Nexus手机");
    }
}

代购商家Seller类,实现了购物接口并持有一个被代理者的引用。

/**
 * 代购商家
 */
public class Seller implements IShop {
    //持有一个被代理者的引用
    private IShop shop;

    public Seller(IShop shop) {

        this.shop = shop;
    }


    public void buy() {
        shop.buy();
    }
}

测试类

/**
 * Client测试类
 */
public class Client {
    public static void main(String[] args) {
        //静态代理
        //创建一个顾客对象
        IShop customer = new Customer();
        //创建一个代购者对象
        Seller seller = new Seller(customer);
        //进行购买操作
        seller.buy();
    }
}

运行结果

买到了Nexus手机

其实也很简单,在以上代理模式的实现方式中,就是利用代理类来持有了被代理类的引用对象,间接调用被代理的方法。

代理模式分类

除了上述代理模式外,代理模式还有其他实现方法,分为以下两种。

静态代理

  静态代理如上述示例那样,代理者的代码由程序员自己或者通过一些自动化工具生成固定的代码再对其进行编译,也就是说在我们的代码运行前代理类的class编译文件就已存在。

动态代理

  动态代理则与静态代理相反,通过反射机制动态地生成代理者的对象,也就是说我们在code阶段压根就不需要知道代理谁,代理谁我们就会在执行阶段决定。

  动态代理的实现可以借助于JDK 实现,也可以使用第三方的字节码生成工具cglib等来实现,下面来看下实现方式。

JDK实现方式

JDK也给我们提供了一个便捷的动态代理接口InvocationHandler,实现该接口需要重写其调用方法invoke.

public class DynamicProxy implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

在这里,我们主要通过invoke方法来调用具体的被代理方法。动态代理可以使我们的代码逻辑更加简洁,但我们首先要完善代理类。

public class DynamicProxy implements InvocationHandler {

    private Object obj;//被代理的类引用

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //调用被代理类对象的方法
        Object result = method.invoke(obj, args);
        return result;
    }
}

如上述代码所示,我们声明一个Object的引用,该引用将指向被代理类,而我们调用被代理类的具体方法则在invoke方法中执行,这样就简洁很多。也就是说我们原来由代理类所做的工作现在由InvocationHandler来处理,不再需要关心到底代理谁。下面我们修改一下上面静态代理的代码。

/**
 * 动态代理实现类
 */
public class DynamicProxy implements InvocationHandler {


    private Object obj;//被代理的类引用

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    /**
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //调用被代理类对象的方法
        System.out.println("执行前");
        Object result = method.invoke(obj, args);
        System.out.println("执行后");
        return result;
    }   
}

测试类


import java.lang.reflect.Proxy;

/**
 * Client类
 */
public class Client {
    public static void main(String[] args) {
         //System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //动态代理
        //构造一个被代理类对象
        IShop customer = new Customer();
        DynamicProxy proxy = new DynamicProxy(customer);
        //获取被代理类的classLoader
        ClassLoader loader = customer.getClass().getClassLoader();
        //动态构造一个代理类
        IShop shop = (IShop) Proxy.newProxyInstance(loader, new Class[]{IShop.class}, proxy);
        //调用方法
        shop.buy();
    }
}

运行结果

执行前
买到了Nexus手机
执行后

可以看到,我们并没有利用到原来的代理类Seller,而是利用动态代理的方式调用Proxy.newProxyInstance()动态生成了一个代理对象,并成功执行了方法。

JDK动态代理的实现原理

跟踪Proxy.newProxyInstance()方法的源码,可以看到程序进行了验证,优化,缓存,同步,生成字节码,显示类加载等操作。
以下是Proxy类的源码,基于sun JDK1.7


package java.lang.reflect;

import java.lang.ref.WeakReference;
import java.lang.reflect.WeakCache.BiFunction;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import sun.misc.ProxyGenerator;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;

public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;


    //代理类的构造函数参数类型
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

 //用于维护类装载器对象到其对应的代理类缓存
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    // 关联的调用处理器引用
    protected InvocationHandler h;

   //构造函数声明为private,禁止实例化
    private Proxy() {
    }

    //由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
    protected Proxy(InvocationHandler h) {
        doNewInstanceCheck();
        this.h = h;
    }
//代理类的访问控制帮助类
    private static class ProxyAccessHelper {
        // The permission is implementation specific.
        static final Permission PROXY_PERMISSION =
            new ReflectPermission("proxyConstructorNewInstance");
        // These system properties are defined to provide a short-term
        // workaround if customers need to disable the new security checks.
        static final boolean allowNewInstance;
        static final boolean allowNullLoader;
        static {
            allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance");
            allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader");
        }

        private static boolean getBooleanProperty(final String key) {
            String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty(key);
                }
            });
            return Boolean.valueOf(s);
        }

        static boolean needsNewInstanceCheck(Class<?> proxyClass) {
            if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) {
                return false;
            }

            if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
                for (Class<?> intf : proxyClass.getInterfaces()) {
                    if (!Modifier.isPublic(intf.getModifiers())) {
                        return true;
                    }
                }
            }
            return false;
        }
    }


     //对实现任何非public类型接口的代理类进行访问检查,如果安全管理器 security manager存在,则调用者无权调用并且会抛出安全异常
    private void doNewInstanceCheck() {
        SecurityManager sm = System.getSecurityManager();
        Class<?> proxyClass = this.getClass();
        if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) {
            try {
                sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION);
            } catch (SecurityException e) {
                throw new SecurityException("Not allowed to construct a Proxy "
                        + "instance that implements a non-public interface", e);
            }
        }
    }

    //返回代理类的java.lang.Class对象,并向其提供类加载器和接口数组
    @CallerSensitive
    public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
        throws IllegalArgumentException
    {
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        return getProxyClass0(loader, intfs);
    }


    private static void checkProxyAccess(Class<?> caller,
                                         ClassLoader loader,
                                         Class<?>... interfaces)
    {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader ccl = caller.getClassLoader();
            if (loader == null && ccl != null) {
                if (!ProxyAccessHelper.allowNullLoader) {
                    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
            ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
        }
    }


     //生成一个代理类,在调用此方法前必须调用checkProxyAccess 进行权限检查
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
         //如果目标类实现的接口数大于65535个则抛出异常
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }


        //如果在缓存中已经找到了对应的代理类,则直接取得缓存,否则将会调用ProxyClassFactory方法来创建一个新的代理类
        return proxyClassCache.get(loader, interfaces);
    }


     // 此key值用于那些未实现接口的代理类
    private static final Object key0 = new Object();


     //此key值用于那些实现了1个接口的代理类
    private static final class Key1 extends WeakReference<Class<?>> {
        private final int hash;

        Key1(Class<?> intf) {
            super(intf);
            this.hash = intf.hashCode();
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf;
            return this == obj ||
                   obj != null &&
                   obj.getClass() == Key1.class &&
                   (intf = get()) != null &&
                   intf == ((Key1) obj).get();
        }
    }


      //此key值用于那些实现了两个接口的代理类
    private static final class Key2 extends WeakReference<Class<?>> {
        private final int hash;
        private final WeakReference<Class<?>> ref2;

        Key2(Class<?> intf1, Class<?> intf2) {
            super(intf1);
            hash = 31 * intf1.hashCode() + intf2.hashCode();
            ref2 = new WeakReference<Class<?>>(intf2);
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            Class<?> intf1, intf2;
            return this == obj ||
                   obj != null &&
                   obj.getClass() == Key2.class &&
                   (intf1 = get()) != null &&
                   intf1 == ((Key2) obj).get() &&
                   (intf2 = ref2.get()) != null &&
                   intf2 == ((Key2) obj).ref2.get();
        }
    }


     //此key值用于那些实现了任意个接口的代理类(这里仅仅用于实现了3个或者三个以上接口的代理类)
    private static final class KeyX {
        private final int hash;
        private final WeakReference<Class<?>>[] refs;

        KeyX(Class<?>[] interfaces) {
            hash = Arrays.hashCode(interfaces);
            refs = new WeakReference[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {
                refs[i] = new WeakReference(interfaces[i]);
            }
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            return this == obj ||
                   obj != null &&
                   obj.getClass() == KeyX.class &&
                   equals(refs, ((KeyX) obj).refs);
        }

        private static boolean equals(WeakReference<Class<?>>[] refs1,
                                      WeakReference<Class<?>>[] refs2) {
            if (refs1.length != refs2.length) {
                return false;
            }
            for (int i = 0; i < refs1.length; i++) {
                Class<?> intf = refs1[i].get();
                if (intf == null || intf != refs2[i].get()) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * A function that maps an array of interfaces to an optimal key where
     * Class objects representing interfaces are weakly referenced.
     */
     //用于产生一组interface到一个最优key之间的映射Map
    private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // 最频繁使用
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }


     //此类根据给定的ClassLoader 和接口数组,生成和定义并返回一个代理类
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        //所有代理类的类名前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        //利用Atomic原子变量产生下一个唯一的代理类名称
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             *生成特定的代理类
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {

                 //类格式异常
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

   //返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }


         //查找或者生成指定的代理类
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
         //调用它的
        try {
        //调用代理对象的构造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        return newInstance(cons, ih);
                    }
                });
            } else {
            //生成代理类的实例并把InvocationHandler传递给它的构造方法
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }

    private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
        try {
            return cons.newInstance(new Object[] {h} );
        } catch (IllegalAccessException | InstantiationException e) {
            throw new InternalError(e.toString());
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString());
            }
        }
    }
    //当且仅当指定的类通过getProxyClass方法或newProxyInstance方法动态生成为代理类时,返回true
       public static boolean isProxyClass(Class<?> cl) {
        return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }

   //返回指定代理实例的调用处理程序
    @CallerSensitive
    public static InvocationHandler getInvocationHandler(Object proxy)
        throws IllegalArgumentException
    {

         //验证对象是否是一个代理类实例
        if (!isProxyClass(proxy.getClass())) {
            throw new IllegalArgumentException("not a proxy instance");
        }

        final Proxy p = (Proxy) proxy;
        final InvocationHandler ih = p.h;
        if (System.getSecurityManager() != null) {
            Class<?> ihClass = ih.getClass();
            Class<?> caller = Reflection.getCallerClass();
            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
                                                    ihClass.getClassLoader()))
            {
                ReflectUtil.checkPackageAccess(ihClass);
            }
        }

        return ih;
    }

    private static native Class defineClass0(ClassLoader loader, String name,
                                             byte[] b, int off, int len);
}

一路跟踪代码,可以发现代码会调用ProxyGenerator类的静态方法generateProxyClass,这里是真正生成代理类class字节码的地方,这个方法可以在运行时产生一个描述代理类的字节码byte[]数组。

generateProxyClass方法源码如下

  public static byte[] generateProxyClass(final String var0, Class[] var1) {
        ProxyGenerator var2 = new ProxyGenerator(var0, var1);
          // 这里动态生成代理类的字节码,比较复杂
        final byte[] var3 = var2.generateClassFile();
       // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
        if(saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    try {
                        FileOutputStream var1 = new FileOutputStream(ProxyGenerator.dotToSlash(var0) + ".class");
                        var1.write(var3);
                        var1.close();
                        return null;
                    } catch (IOException var2) {
                        throw new InternalError("I/O exception saving generated file: " + var2);
                    }
                }
            });
        }
     // 返回代理类的字节码 
        return var3;
    }

既然生成了代理类的字节码,那么我们能拿到它的字节码吗?答案是肯定的。如果想看一看这个在运行时产生的代理类写了些什么,可以在main()方法中加入下面这句:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

这句代码告诉JVM 在将生成的字节码保存下来,默认的保存为项目根路径的com/sun/proxy/,需要手动在项目根目录创建这个路径,不然会报找不到路径的错误,如下所示


java.lang.InternalError:
I/O exception saving generated file: java.io.FileNotFoundException: com/sun/proxy/$Proxy0.class (No such file or directory)

运行程序可以发现 在com/sun/proxy/路径下生成了$Proxy0.class字节码文件,反编译后可以看到它的源码如下:

package com.sun.proxy;

import chapter18.IShop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IShop {
    private static Method m1;
    private static Method m3;
    private static Method m0;
    private static Method m2;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    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);
        }
    }

    public final void buy() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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);
        }
    }

    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 {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("chapter18.IShop").getMethod("buy", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", 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());
        }
    }
}

  这个代理类的实现代码也很简单,它为传入接口中的每一个方法,以及从java.lang.Object中继承来的equals(),hashCode(),toString()方法都生成了对应的实现,并且统一调用了InvocationHandler对象的invoke()方法(代码中的”this.h”就是父类Proxy中保存的InvocationHandler实例变量)来实现这些方法的内容,各个方法的区别不过是传入的参数和Method对象有所不同而已,所以无论调用动态代理的哪一个方法,实际上都是在执行InvocationHandler.invoke()中的代理逻辑。

  从以上的分析中可以看到JDK 的精妙设计,开发者不需要关心代理类的生成逻辑,这也是AOP编程方式的基本原理。

JDK 动态代理缺点

  但是这种方式的缺憾在于 被代理类必须实现接口,那些没有实现接口的类将无法采用JDK动态代理方式生成代理类。
这是因为辅助生成的代理类将默认继承自Proxy类,Java本身只支持单继承,不能再借助于继承方式,所以只能通过接口方式拿到具体的方法,看一下生成后的代理类$Proxy0.class的源码什么都明白了。

那有什么方式可以弥补这种缺憾呢?一种称为字节码生成技术的方案可以解决这个问题。

“字节码生成”并不是什么高深的技术,常见的字节码生成方案有Javassist,CGLib,ASM之类的字节码类库,但其实JDK 里面的javac命令就是字节码生成技术的”老祖宗”,javac也是一个由Java语言写成的程序,将java源程序编译成与平台无关虚拟机可以识别的字节码。

下面介绍一种方案,被代理类可以不用实现任何接口即可进行动态代理。

CGLib实现

  CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

被代理类

/**
 * 顾客类
 */
public class Customer {
    public void buy() {
        System.out.println("买到了Nexus手机");
    }
}



动态代理实现类

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * CGLib实现动态代理
 */
public class CustomerCglib implements MethodInterceptor {


    public Object getProxy(Class clazz) {
        Enhancer enhancer = new Enhancer();
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        //回调方法
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();


    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行前");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("执行后");
        return result;
    }
}

测试类

/**
 * 测试类
 */
public class Client {
    public static void main(String[] args) {
        CustomerCglib cglib = new CustomerCglib();
        Customer customer = (Customer) cglib.getProxy(Customer.class);
        customer.buy();
    }
}

  CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

其他分类方式

  • 远程代理
    为某个对象在不同的内存地址空间提供局部代理。使系统可以将Server部分的实现隐藏,以便Client可以不必考虑Server的存在。
  • 虚拟代理
    使用一个代理对象表示一个十分消耗资源的对象并在真正需要时才创建。
  • 保护代理
    使用代理控制对原始对象的访问。该类型的代理场被用于原始对象有不同访问权限的情况。
  • 智能引用
    在访问原始对象时执行一些自己的附加操作并对指向原始对象的引用计数。

这里要注意的是,静态和动态代理都可以应用于上述4种情形,两者是各自独立的变化。


参考资料

  1. 《Android 源码设计模式解析与实战》
  2. 《深入理解Java虚拟机》
  3. 《Java 动态代理机制分析及扩展》
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值