目录
-
什么是代理模式?
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
通俗的来讲代理模式就是我们生活中常见的中介。
现实中的例子:租房中介、火车票黄牛、媒人、经纪人。
代理模式注重过程,代理人有权利决定是否通知被代理人。
-
代理模式三个必要条件
- 代理人、被代理人。
- 对于被代理人,这件事一定要做,但自己不想亲自做,找代理。
- 代理人需要获取被代理人的个人资料(执行者持有被代理对象的引用)。
-
代理模式分类
静态代理:在程序运行之前.class文件已经存在了。静态代理工作量大,不易管理与维护。
动态代理:在程序运行期间,通过反射的方式动态的创建出来。动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。
-
JDK动态代理
JDK的动态代理必须具备四个条件:1、目标接口 2、目标类 3、拦截器 4、代理类
-
实现原理
- 获取目标类对象上的所有接口列表;
- 确定要生成的代理类的类名;
- 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
- 将对应的字节码转换为对应的class 对象;
- 创建InvocationHandler 实例handler,用来处理Proxy所有方法调用;
- Proxy 的class对象以创建的handler对象为参数,实例化一个proxy对象。
- proxy对象执行具体业务的过程,实际是执行代理类中handler对象的invoke方法,同时把被代理方法和参数传进去,在invoke方法中执行代理逻辑与被代理逻辑。
-
JDK动态代理缺点
- 目标类必须实现至少一个接口。
- 目标类方法内部调用无法产生增强效果,必须通过代理类才能生效。
-
如何手写模拟JDK动态代理
自定义MyClassLoader,MyInvocationHandle,MyPorxy
MyClassLoader:代码生成、编译、重新动态load到JVM。
MyInvocationHandle:代理类需要实现的接口,重写invoke方法,实现代理业务逻辑。
MyPorxy:生成代理对象的代码。
过程:
- 生成源代码;将生成的源代码输出到磁盘,保存为.java文件;
- 编译源代码,并且生成.class文件;
- 将class文件中的内容,动态加载到JVM中;
- 返回被代理后的代理对象。
-
CGLIB动态代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。底层依靠ASM操作字节码实现。
特点:
- CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
- 用CGlib生成代理类是目标类的子类。
- 用CGlib生成的代理类不需要接口。
- 用CGlib生成的代理类重写了父类的各个方法。
- 拦截器中的intercept方法内容正好就是代理类中的方法体。
-
CGLIB动态代理缺点
- 因为采用继承,所以不能对final修饰的类或方法进行代理。
- 需要额外进入CGlib类库。
-
CGLIB和JDK动态代理比较
JDK:
- 目标类和代理类实现了共同的接口。
- 拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方法体的内容。
CGLIB:
- 目标类是代理类的父类。
- 拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体,使用字节码增强机制创建代理对象的。
-
动态代理的应用场景
事务管理、日志管理、权限管理、缓存等。