Java高级--动态代理

什么是代理模式?

代理模式就是为其他对象提供一种代理来对该对象进行访问控制。

​ 生活实例:

​ 1)房产中介,他就是一个代理,由房东全权授权中介来进行房产的售前咨询,相关事宜的处理等。

​ 2)滴滴代驾,就是授权代驾可以驾驶你的车辆,并将车辆行驶至目的地,期间代驾可以进行对车辆的一些简单的操作。

代理---“铁三角”:

  1. 抽象角色:

    为“代理角色”和“真实角色”提供的一套对外的公共方法(一般定义为接口)
interface ProxyInterface {
    fun confirmAction(inputString :String,name:String);
}
  1. 真实角色:

    ​ 真正的业务实现逻辑,他需要实现“抽象角色”中的接口;

class RealInstance : ProxyInterface {

    private val TAG  = "RealInstance";
    override fun confirmAction(inputString: String,name: String) {
        Log.e(TAG,"真实实例对象----"+"调用confirmAction()")
    }
}
  1. 代理角色:

    ​ 他同“真实角色”一样,实现了“抽象角色”中的接口,同时拥有对“真实角色”的引用,然后通过“真实角色”的引用来实现“抽象角色”中的抽象方法,且可以自己在抽象方法中增加自己的一些操作等。

class ProxyInstance(realInstance: RealInstance) : ProxyInterface {
    val TAG = "ProxyInstance";

    var mRealInstance: RealInstance = realInstance
    override fun confirmAction(inputString: String,name:String) {
        Log.e(TAG, "我是代理,我的confirmAction被调用")
        mRealInstance.confirmAction(inputString,name)
    }
}

​ 三者之间的类关系如图所示:


铁三角类图.png

了解了上面的“铁三角”,那相信我们对代理模式就已经完全明白了代理模式了。。。。很简单吧!!!!别高兴的太早了,一步一步带你进去深渊。。。。

代理的用途:

  1. 通过引入代理对象的方式来间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性;
  2. 通过代理对象进行对访问的控制;

好,那我们就来聊聊怎么使用? 今天先聊一下静态代理和动态代理。

代理使用:

1)静态代理:

​ 顾名思义,就是我们在实现代理模式时,在编辑阶段就需要将对象的代理者都准备好,在程序运行时使用。

val proxyInstance = ProxyInstance(RealInstance())
proxyInstance.confirmAction("测试代理模式","")

缺点:

1.当需要代理的真实角色多时,我们的代理对象是不是也需要很多,这样就会出现代理对象和代码量变大的情况

2.如果我们想要扩展一下抽象接口的方法,那么真实角色和代理角色都需要维护,这样是不是维护、扩展能力也比较差

​ 既然静态代理有那么明显的缺点,我们有没有办法解决呢,答案是肯定的,这就是我们下面的动态代理。

2)动态代理:

​ 相对于静态代理而言,动态代理则是在程序运行时再创建对象的代理类和实例,也就是说有程序帮我们去创建代理类及其实例,这样效率很明显要低些。

JDK已经为我们提供好了API了,我们直接用JDK API就可以了,如下:

 val newProxyInstance = Proxy.newProxyInstance(RealInstance::class.java.classLoader,
                arrayOf(ProxyInterface::class.java),
                object : InvocationHandler {
                    override fun invoke(proxy: Any?, method: Method?, args: Array?): Any? {
                        if (args?.size!! > 1) {
                            return method?.invoke(RealInstance(), args[0],args[1])
                        }
                        return null
                    }
                }
            ) as ProxyInterface

newProxyInstance.confirmAction("hello","我是代理对象");   

上述代码中,有两个关键的API: Proxy和InvocationHandler,下面我们就深入“敌营”来了解一下。

源码剖析:

Proxy 提供了创建动态代理类和实例的静态方法,它也是有这些方法穿件的所有动态代理类的超类。是一个实现在运行时进行创建直接接口列表的类。

先来看看动态代理实现的流程图,


动态代理原理流程图.jpg

然后再看源码,下面源码已经做了详细的备注。

Proxy 类中的成员变量和方法:

package java.lang.reflect;//在此包下

/////////////////////////////////////////////////////////////////////////////////

//静态成员

  private static final Class[] constructorParams =
        { InvocationHandler.class };


/**
* 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。 
*----loader - 类加载器来定义代理类---当前真实角色的类加载器
*----interfaces - 代理类实现的接口列表   他是一个数组:因为一个代理可以代理多个实例对象
*----h - 调度方法调用的调用处理函数 
*/
  @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        //复制一份抽象接口类,并保存到数组中
        final Class[] intfs = interfaces.clone();

        /*
         * Look up or generate the designated proxy class.
         * 查找或生成代理类
         */
        Class cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            //获取代理类的public构造方法的引用
            final Constructor cons = cl.getConstructor(constructorParams);//constructorParams 静态成员
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                cons.setAccessible(true);
            }
            
            //使用带指定参数:h的构造器cons来生成该构造器所代表的代理类的实例,并将该代理类实例返回
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }


///////////////////////////////////////////////////////////
  /**
     * a cache of proxy classes
     代理类的缓存
     */
    private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());


 /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     
     从缓存中读取代理类,如果存在则直接返回该代理类,否则创建该代理类
     */
    private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

代理的缓存WeakCache

package java.lang.reflect;


 public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        //使用外部传入的key 生成cacheKey
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
     //线程安全的原子操作担保 ConcurrentMap
        ConcurrentMap> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            //从原缓存map中查找cacheKey ,如果找不到则创建一个新的map 添加到缓存map中,并将新的map一起返回
            ConcurrentMap> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier stored by that
        // subKey from valuesMap
         //1.使用可以生成subkey ,从新的map获取可以对应的Supplier提供者
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier supplier = valuesMap.get(subKey);
        Factory factory = null;

         //无限循环来查找值,如果找到就返回,没有找到就创建一个新的值
        while (true) {
            
            if (supplier != null) {
                //找到值
                // supplier might be a Factory or a CacheValue instance
                //如果supplier不为空,则直接取出supplier中的值返回
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            //准备创建
            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

Invocationhandler接口类

//每一个代理类实例有一个相对应的InvocationHandler句柄,一旦代理类实例调用了其中一个method方法都会触发该句柄的invoke方法,并将相关信息返回
//1 proxy 代理类实例
//2 method ,调用的方法,
//3 args   该用法的参数
public interface InvocationHandler {
    
 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

ProxyClassFactory 最终类通过反射来生成代理类

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

            Map, 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
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * 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)) {
                    accessFlags = Modifier.FINAL;
                    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 the default package.
                proxyPkg = "";
            }

            {
                // Android-changed: Generate the proxy directly instead of calling
                // through to ProxyGenerator.
                List methods = getMethods(interfaces);
                Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                validateReturnTypes(methods);
                List[]> exceptions = deduplicateAndGetExceptions(methods);

                Method[] methodsArray = methods.toArray(new Method[methods.size()]);
                Class[][] exceptionsArray = exceptions.toArray(new Class[exceptions.size()][]);

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

                return generateProxy(proxyName, interfaces, loader, methodsArray,
                                     exceptionsArray);
            }
        }
    }

说了半天的动态代理,那么动态代理到底生成的类长啥样呢,我们如何才可以看到呢?

查询动态代理类

  1. 新建一个java module
  2. 将上述抽象接口和真实角色的class 考入java module中
  3. 新建一个ProxyUtils类
 public static void generateClassFile(Class clazz,String proxyName)
    {
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String path = clazz.getResource(".").getPath();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path + proxyName + ".class");
            fos.write(classFile);
            fos.flush();
        }catch(Exception e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Subject subject=new Subject();//此处为真实角色的对象
        ProxyInterface proxy =(ProxyInterface) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
                new Class[]{ProxyInterface.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        return null;
                    }
                });
        generateClassFile(Subject.class,"SubjectProxy");//第二个参数是生成的代理类名
        proxy.confirmAction();
    }
  1. 运行ProxyUtils类的Main函数,则会在build/classes/java/main/com/XXX/proxylib/目录下生成 SubjecProxy.class文件
  2. 分析一下这个class文件

    1.他是一个最终类,并且继承Proxy ,实现了我们自己的抽象接口ProxyInterface
    2.有一个public 修饰的构造函数,并且InvocationHandler作为参数
    3.重写了Object的equals()、toString()、hasCode()方法
    4.实现了抽象接口ProxyInterface的方法,方法体是使用InvocationHandler实例来调用它的invoke方法,并将代理实例、方法、参数作为参数回调回去
    5.静态代码区:通过反射实现类名和方法的反射,并将反射的method存放到静态变量中

实际运行生成的代码如下:

public final class SubjectProxy extends Proxy implements ProxyInterface {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public SubjectProxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

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

    public final void confirmAction() 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);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.leon.proxylib.ProxyInterface").getMethod("confirmAction");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

到此为止,已经将java的动态代理,代理模式包括相关源码的剖析都已经介绍完了,有需要的同学的可以自己跟着上面的额内容实操一下加强记忆。

知识点总结:

1、设计模式---代理模式

2、调用处理器InvocationHandler

3、Java反射机制

4、Map缓存机制

今天就学习到这里了,欢迎来踩点

你可能感兴趣的:(Java高级--动态代理)