🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
上篇博客由于长度的原因,只是用代码展示了静态代理到动态代理的“进化”。那么本篇博客就动态代理的实现原理做一个介绍,从而有一个更深入的理解。当然,这也已经渐渐的脱离的代理模式的内容,因为学习是一个管中窥豹的过程,了解的越深入才能了解事务的本质。 ## 问题重现 动态代理呢解决了静态代理的两个在一定条件下不适应的问题:其一,因为代理类中需要持有一个实际类而导致的代理类和实际类的耦合度过高的问题。其二,当接口的方法过多时,代理类的重复代码过多的问题。第一个问题是通过Proxy类的newProxyInstance方法动态的创建代理类解决的。第二个问题则是通过一个继承了InvocationHandler接口的类的invoke方法解决的。这里有三个关键词,分别是:动态、Proxy、InvocationHandler。下面我们一一解释! ## 动态 动态是指在运行状态下加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,并生成其对象实体、或改变其属性、或唤起其methods。那么放到动态代理里就是说,代理类在程序运行之前是不存在的,而是在程序运行中才创建的。即在程序运行中才有实际的代理类产生并实例话。 ## InvocationHandler接口 静态代理的第二个问题是,每个代理的方法都要加上相同内容的代码,重复代码太多。实现了这个接口的类,是作为代理类的一个关联存在的。也就是说这个类是面对代理类中的所有方法的,它把代理类的功能分成了两个部分。对方法的加强放在了这个类里,而代理类则只实现对实际类的方法调用。 这个接口中只有一个Invoke方法这个方法就是对代理类的方法的加强。它实际是对代理方法的一个拦截处理,也就是说当调用代理类中的方法时,不论哪一个都相当于调用了Invoke方法。而在Invoke方法中对代理的方法做了一个包装加强。Invoke方法有三个参数如下: ~~~ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //代码略 } ~~~ proxy :在其上调用方法的代理实例 method:对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。 args: 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。 ## Proxy类 这个类是动态的产生代理类的关键,先看看下表对该类的方法有些了解。这其中目前我觉得比较重要的是NewProxyInstance方法。所以这个介绍一下,其他的就查Java的api文档吧。 ![](https://box.kancloud.cn/2016-02-19_56c6b93c69722.jpg) ~~~ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)<span style="font-family: FangSong_GB2312;">              </span> ~~~ 参数: loader - 定义代理类的类加载器 interfaces - 代理类要实现的接口列表 h - 指派方法调用的调用处理程序 返回: 一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口               **总结**:到这里动态代理包含的内容都做了基本介绍,那么经过这几天的学习呢其实动态代理我们只要分开两个过程看,一个是代理的创建过程如下图,一个是代理模式的实现,这个就不上图了。这里需要强调的是代理模式的类图在动态代理中具有时间性,因为没有创建代理之前那么代理模式是不存在的。 ![](https://box.kancloud.cn/2016-02-19_56c6b93c79b68.jpg) 那么这里真正新奇的东西是Proxy类中的newProxyInstance方法,几个参数的说明都是莫名其妙的。这里涉及到java的另一知识:反射机制。而动态代理只是它的一个典型应用。那么下篇博客再见了,反射机制!