4(实战):静态代理+ JDK/CGLIB 动态代理(文末有项目连接)

1:什么是代理模式
代理模式是一种比较好理解的设计模式。
我们使用代理对象来代替真实对象的访问,这样子就可以在不修改原目标对象的前提下,

提供额外的功能操作,扩展目标对象的功能。
2:静态代理
实际应用场景非常少

静态代理中:我们对目标对象的每个方法的增强都是手动完成的
如:某个接口一旦新增了方法,代理对象和目标对象都要进行修改 

从JVM层面上:静态代理就是在编译时将接口、实现类、代理类变成一个个class文件,

1:定义一个接口和其实现类
2:创建一个代理类同样实现这个接口
3:将目标对象注入到代理类,然后在代理类的对应方法 调用目标类中的方法。
    我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己的事情
3:动态代理
相对于静态代理来说,动态代理更加灵活。
我们不需要针对每个目标都独立创建一个个代理类,并且也不需要我们必须实现接口;

从JVM角度来说,动态代码在运行时动态生成类字节码,并加重到JVM中的。

其中Spring AOP 和 RPC框架的实际都是依赖离开动态代理;

动态代理又分  JDK动态代理  和 CGLIB动态代理
4:JDK动态代理
Spring AOP 中默认的代理方式   注意:只能代理实现了接口的类

具体调用流程:
    在通过Proxy类的 newProxyInstance()创建的代理对象调用方法的时候,
    实际会调用到实现InvocationHandler类的 invoke()方法。
    可以在 invoke()方法自定义处理逻辑。

 具体实现流程
    1:定义一个接口及其实现类;
    2:通过 Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)  创建代理对象
    3:自定义InvocationHandler 并重写 invoke方法,
        在invoke方法中调用被代理类的的方法并自定义一些处理逻辑。

Proxy类中使用频率最高的方法是:newProxyInstance() 主要用于生成一个代理对象

newProxyInstance方法中的三个参数
    1:loader:类加载器 用于加载代理对象;
    2:interfaces:被代理的一些接口;
    3:h:实现了InvocationHandler 接口的对象;
     public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 
        throws IllegalArgumentException 
        { ...... }
       

自定义InvocationHandler类中的 invoke 为反射方法

invoke方法中的三个参数
    1:proxy:动态生成的代理类
    2:method:与代理类对象调用的方法相对应
    3:args:当前method方法的参数
      public interface InvocationHandler {
        /** * 当你使用代理对象调用方法的时候实际会调用到这个方法 */ 
        public Object invoke(Object proxy, Method method, Object[] args) 
         throws Throwable; 
    }

5:CFLIB动态代理
JDK动态代理有一个致命的问题:只能代理实现了接口的类

GCLIB通过继承的方式实现代理,
例如在Spring中的AOP模块中:如果目标对象实现了接口,则默认采用JDK动态代理,否则使用CGLIB动态代理。

具体调用流程:
    在通过Enhancer类的 create()创建的代理对象调用方法的时候,
    实际会调用到实现MethodInterceptor 类的intercept()方法。
    可以在 intercept()方法自定义处理逻辑。

 具体实现流程
    1:定义一个类;
    2:通过 Enhancer 类的create() 创建代理类
    3:自定义MethodInterceptor 并重写 intercept方法,
        在intercept方法中调用被代理类的的方法并自定义一些处理逻辑。

Enhancer类 为cglib.proxy.Enhancer 该包下的 动态代理增强类
    // 创建动态代理增强类
    Enhancer enhancer = new Enhancer();
    // 设置类加载器
    enhancer.setClassLoader(clazz.getClassLoader());/
    // 设置被代理类
    enhancer.setSuperclass(clazz);
    // 设置方法拦截器
    enhancer.setCallback(new MyMethodInterceptor());
    // 创建代理类
    return enhancer.create();

自定义MyMethodInterceptor 类中的  intercept 方法
 
 intercept 方法中的四个参数:
  1:obj  :    被代理的对象(需要增强的对象)
  2:method : 被拦截的方法(需要增强的方法)
  3:objects : 方法入参
  4:methodProxy :用于调用原始方法
    public interface MethodInterceptor extends Callback{ 
    // 拦截被代理类中的方法 
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy)
        throws Throwable;
    }    
6:静态代理和动态代理的区别总结
灵活性:
    静态代理中接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的;
    动态代理更加灵活,可以直接代理实现类,并不需要针对每一个目标类都创建一个代理类。

JVM层面:
    静态代理在编译时就将接口、实现类、代理类这些变成一个个实际的class文件
    动态代理在运行期动态生成类字节码 并 加载到JVM中
7:JDK动态代理 和 CGLib动态代理 区别
1:JDK动态代理是⾃带的,CGlib需要引⼊第三⽅包

2:JDK动态代理,要求⽬标对象实现⼀个接⼝,
    但是有时候⽬标对象只是⼀个单独的对象,并没有实现任何的接⼝,这个时候就可以⽤CGLib动态代理

3:CGLib动态代理,它是在内存中构建⼀个⼦类对象从⽽实现对⽬标对象功能的扩展
    CGLib动态代理基于继承来实现代理,所以⽆法对final类、private⽅法和static⽅法实现代理

Spring AOP中的代理使⽤的默认策略?
    如果⽬标对象实现了接⼝,则默认采⽤JDK动态代理
    如果⽬标对象没有实现接⼝,则采⽤CgLib进⾏动态代理
    如果⽬标对象实现了接⼝,程序⾥⾯依旧可以指定使⽤CGlib动态代理

项目连接

请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/rpc-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/rpc-project.git

rpc-project-demo模块下  proxyDemo包      

你可能感兴趣的:(4(实战):静态代理+ JDK/CGLIB 动态代理(文末有项目连接))