目录
代理模式的基本介绍
静态代理
动态代理
Cglib 代理
代理模式的基本介绍
代理模式: 为一个对象提供一个替身, 以控制这个对象的访问, 即通过代理对象访问目标对象, 这样做的好处是, 可以在目标对象的基础上, 增强额外的功能操作, 即扩展目标对象的功能
代理模式有不同的模式, 主要有三种 静态代理, 动态代理, Cglib 代理
其中 动态代理也被称为 JDK 代理或者接口代理, 有些书把 Cglib 代理也划为动态代理, 这些也是可以的, 这里我之所以把 Cglib 代理单独拆分出来, 是因为使用 Cglib 代理时, 被代理类可以无需实现接口
代理模式 UML 类图
静态代理
这种代理方式需要代理对象和目标对象实现一样的接口.
优点: 可以在不修改目标对象的前提下扩展目标对象的功能.
缺点:
冗余. 由于代理对象要实现与目标对象一致的接口, 会产生过多的代理类.
不易维护. 一旦接口增加方法, 目标对象与代理对象都要进行修改.
举例: 老师授课的静态代理
接口类
- public interface ITeacherDao {
- void teach();
- }
目标对象
- public class TeacherDao implements ITeacherDao{
- @Override
- public void teach() {
- System.out.println("老师授课");
- }
- }
代理类
- public class TeacherDaoProxy implements ITeacherDao{
- private ITeacherDao target;
- public TeacherDaoProxy(ITeacherDao target){
- this.target = target;
- }
- @Override
- public void teach() {
- System.out.println("代理开始");
- target.teach();
- System.out.println("代理结束");
- }
- }
测试类
- public class Client {
- public static void main(String[] args) {
- // 创建目标对象
- ITeacherDao target = new TeacherDao();
- TeacherDaoProxy proxy = new TeacherDaoProxy(target);
- proxy.teach();
- }
- }
输出结果
代理开始
老师授课
代理结束
动态代理
动态代理利用了 JDK API http://tool.oschina.net/uploads/apidocs/jdk-zh/ , 动态地在内存中构建代理对象, 从而实现对目标对象的代理功能. 动态代理又被称为 JDK 代理或接口代理.
静态代理与动态代理的区别主要在:
静态代理在编译时就已经实现, 编译完成后代理类是一个实际的 class 文件
动态代理是在运行时动态生成的, 即编译完成后没有实际的 class 文件, 而是在运行时动态生成类字节码, 并加载到 JVM 中
特点:
动态代理对象不需要实现接口, 但是要求目标对象必须实现接口, 否则不能使用动态代理.
JDK 中生成代理对象主要涉及的类有:
java.lang.reflect Proxy, 主要方法为
- static Object newProxyInstance(ClassLoader loader, // 指定当前被代理对象使用类加载器
- Class<?>[] interfaces, // 被代理对象实现的接口的类型
- InvocationHandler h // 事件处理器
- )
- // 返回一个指定接口的代理类实例, 该接口可以将方法调用指派到指定的调用处理程序.
java.lang.reflect InvocationHandler, 主要方法为
- Object invoke(Object proxy, Method method, Object[] args)
- // 利用反射, 在代理实例上处理方法调用并返回结果.
举例: 老师授课动态代理
接口类
- // 接口
- public interface ITeacherDao {
- void teach();
- }
目标对象
- public class TeacherDao implements ITeacherDao{
- @Override
- public void teach() {
- System.out.println("老师授课中");
- }
- }
代理类
- public class ProxyFactory {
- // 维护一个目标对象
- private Object target;
- // 构造器对 target 进行初始化
- public ProxyFactory(Object target){
- this.target = target;
- }
- // 给目标对象生成一个代理对象
- public Object getProxyInstance(){
- /**
- * 1.ClassLoader loader: 指定当前目标对象使用的类加载器, 获取加载器的方法固定
- * 2.Class<?>[] interfaces: 目标对象实现接口的类型, 使用泛型方法确认类型
- * 3.InvocationHandler h: 事件处理 执行目标对象的方法时, 会触发事件处理方法
- */
- return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("------ 代理开始 -------");
- Object returnVal = method.invoke(target, args);
- System.out.println("------ 代理结束 -------");
- return returnVal;
- }
- });
- }
- }
测试类
- public class Client {
- public static void main(String[] args) {
- ITeacherDao target = new TeacherDao();
- System.out.println("target:"+target.getClass());
- ITeacherDao proxy = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
- proxy.teach();
- System.out.println("proxy:" + proxy.getClass());
- }
- }
输出结果
target:class com.proxy.dynamicproxy.TeacherDao
------ 代理开始 -------
老师授课中
------ 代理结束 -------
proxy:class com.sun.proxy.$Proxy0
Cglib 代理
https://github.com/cglib/cglib (Code Generation Library ) 是一个第三方代码生成类库, 运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展.
cglib 特点
JDK 的动态代理有一个限制, 就是使用动态代理的对象必须实现一个或多个接口.
如果想代理没有实现接口的类, 就可以使用 CGLIB 实现.
CGLIB 是一个强大的高性能的代码生成包, 它可以在运行期扩展 Java 类与实现 Java 接口.
它广泛的被许多 AOP 的框架使用, 例如 Spring AOP 和 dynaop, 为他们提供方法的 interception(拦截).
CGLIB 包的底层是通过使用一个小而快的字节码处理框架 ASM, 来转换字节码并生成新的类.
不鼓励直接使用 ASM, 因为它需要你对 JVM 内部结构包括 class 文件的格式和指令集都很熟悉.
注: cglib 与动态代理最大的区别就是 被代理对象是否必须实现接口
示例: 老师授课 cglib 代理
maven 依赖, 注: 如果你已经有 spring-core 的 jar 包, 则无需引入, 因为 spring 中包含了 cglib
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>3.2.5</version>
- </dependency>
目标对象
- public class TeacherDao {
- public void teach(){
- System.out.println("老师授课");
- }
- }
代理类
- public class ProxyFactory implements MethodInterceptor{
- // 维护一个目标对象
- private Object target;
- // 构造器 传入一个被代理对象
- public ProxyFactory(Object target){
- this.target = target;
- }
- // 返回一个代理对象: 是 target 对象的代理对象
- public Object getProxyInstance(){
- //1. 创建一个工具类
- Enhancer enhancer = new Enhancer();
- //2. 设置父类
- enhancer.setSuperclass(target.getClass());
- //3. 设置回调函数
- enhancer.setCallback(this);
- //4. 创建子类对象 即代理对象
- return enhancer.create();
- }
- @Override
- public Object intercept(Object arg0, Method method, Object[] args,
- MethodProxy arg3) throws Throwable {
- System.out.println("-------- 代理开始 -------");
- Object returnVal = method.invoke(target, args);
- System.out.println("-------- 代理结束 -------");
- return returnVal;
- }
- }
测试类
- public class Client {
- public static void main(String[] args) {
- TeacherDao target = new TeacherDao();
- ProxyFactory proxyFactory = new ProxyFactory(target);
- TeacherDao proxy = (TeacherDao)proxyFactory.getProxyInstance();
- proxy.teach();
- System.out.println(proxy.getClass());
- }
- }
输出结果
-------- 代理开始 -------
老师授课
-------- 代理结束 -------
class com.dw.cglib.TeacherDao$$EnhancerByCGLIB$$e99265d4
来源: https://www.cnblogs.com/dwlovelife/p/11161666.html