代理模式详解——动态代理(待完善)

动态代理
动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩
展适应性更强。如果还以找对象为例,使用动态代理相当于是能够适应复杂的业务场景。
不仅仅只是父亲给儿子找对象,如果找对象这项业务发展成了一个产业,进而出现了媒
婆、婚介所等这样的形式。那么,此时用静态代理成本就更大了,需要一个更加通用的
解决方案,要满足任何单身人士找对象的需求。我们升级一下代码,先来看JDK 实现方
式:

JDK 实现方式
创建媒婆(婚介)JDKMeipo 类:

package com.gupaoedu.vip.pattern.proxy.dynamicproxy.jdkproxy;
import com.gupaoedu.vip.pattern.proxy.staticproxy.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKMeipo implements InvocationHandler{
//被代理的对象,把引用给保存下来
  private Object target;
   public Object getInstance(Object target) throws Exception{
     this.target = target;
     Class<?> clazz = target.getClass();
     return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     before();
     Object obj = method.invoke(this.target,args);
      after();
     return obj;
}
private void before(){

System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
System.out.println("开始物色");
}
private void after(){
System.out.println("如果合适的话,就准备办事");
}
}
创建单身客户Customer 类:

package com.gupaoedu.vip.pattern.proxy.dynamicproxy.jdkproxy;
import com.gupaoedu.vip.pattern.proxy.Person;
   public class Customer implements Person{
       public void findLove(){
       System.out.println("高富帅");
     System.out.println("身高180cm");
      System.out.println("胸大,6 块腹肌");
}
}
测试代码:

public static void main(String[] args) {
   try {
      Person obj = (Person)new JDKMeipo().getInstance(new Customer());
     obj.findLove();
      } catch (Exception e) {
     e.printStackTrace();
     }
}

代理模式详解——动态代理(待完善)

不仅知其然,还得知其所以然。既然JDK Proxy 功能如此强大,那么它是如何实现的呢?
我们现在来探究一下原理,并模仿JDK Proxy 自己动手写一个属于自己的动态代理。
我们都知道JDK Proxy 采用字节重组,重新生的对象来替代原始的对象以达到动态代理
的目的。JDK Proxy 生成对象的步骤如下:
1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2、JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接
口。
3、动态生成Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体
现)。
4、编译新生成的Java 代码.class。
5、再重新加载到JVM 中运行。

 

 

CGLib 动态代理执行代理方法效率之所以比JDK 的高是因为Cglib 采用了FastClass 机
制,它的原理简单来说就是:为代理类和被代理类各生成一个Class,这个Class 会为代
理类或被代理类的方法分配一个index(int 类型)。这个index 当做一个入参,FastClass
就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK
动态代理通过反射调用高。

CGLib 和JDK 动态代理对比
1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
2.JDK 和CGLib 都是在运行期生成字节码,JDK 是直接写Class 字节码,CGLib 使用ASM
框架写Class 字节码,Cglib 代理实现更复杂,生成代理类比JDK 效率低。
3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过FastClass 机制直接调用方法,
CGLib 执行效率更高。

 

 

静态代理和动态的本质区别
1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步
新增,违背开闭原则。
2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开
闭原则。
3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,
无需修改代理类的代码。

 

代理模式的优缺点
使用代理模式具有以下几个优点:
1、代理模式能将代理对象与真实被调用的目标对象分离。
2、一定程度上降低了系统的耦合度,扩展性好。
3、可以起到保护目标对象的作用。
4、可以对目标对象的功能增强。
当然,代理模式也是有缺点的:

1、代理模式会造成系统设计中类的数量增加。
2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
3、增加了系统的复杂度。