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包