设计模式之代理模式


  代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

作用:

  • 1.检测类中方法的执行
  • 2.可以在类中所有的或者某一个方法执行的过程中 动态的植入代码进行运行

特点:
  由被代理角色来做最终决定,代理角色通常来说会持有被代理角色对象的引用,以便于代理角色完成工作之前或者之后能够找到代理对象,能够通知被代理对象

分类: 静态代理,动态代理

一、代理

1. 静态代理

  代理前所有的东西已知的(人工化)
静态代理类持有被代理类的引用,是具体的类;一般代理类实现和被代理相同的接口,如果被代理的接口修改,代理也会修改,复杂也麻烦。

2.动态代理

  代理前所有的东西未知的((自动化的)

2.1 JDK代理

  持有的代理引用可以不是具体的类,给一个接口就可以了;生成的代理类和被代理的类是同级的。

person接口:

package com.vison.proxy.jdkproxy;

public interface Person {
    void findLove();
}

被代理类:

public class LiSi implements Person {
    public void findLove() {
        System.out.println("need find love");
    }
}

代理类,实现InvocationHandler接口

package com.vison.proxy.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy implements InvocationHandler {

    private Person person;

    public Object getInstance(Person person) {
        this.person = person;
        Class clazz = person.getClass();
        return  Proxy.newProxyInstance(person.getClass().getClassLoader(),clazz.getInterfaces(),this);
    }

	//代理,这里可以做相应的方法处理
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before to do method");
        Object invoke = method.invoke(person, args);
        System.out.println("after to do method");
        return invoke;  //这里是返回方法调用的结果
    }
}

测试:

package com.vison.proxy.jdkproxy;

public class TestJdk {

    public static void main(String[] args) {
        Person person = (Person)new JdkProxy().getInstance(new LiSi());
        person.findLove();
        System.out.println("--------------"+person.getClass());

    }
}
2.2 CGLIB代理

  CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的
  Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.

被代理类:

package com.vison.proxy.cglib;

public class ZhouYu {

    String findLove(){
        System.out.println("easy to find love");
        return "success";
    }
}

代理类:

package com.vison.proxy.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CgLibProxy implements MethodInterceptor {

    public Object getInstance (Class<?> clazz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //业务的增加
        System.out.println("before to do method");
        System.out.println("methodProxy--------"+methodProxy.getClass());
        System.out.println("object---------"+proxy.getClass());

		//这里调用invokeSuper方法
        Object ans = methodProxy.invokeSuper(proxy, objects);
        System.out.println("after to do method");
        return ans;
    }
}

测试:

package com.vison.proxy.cglib;

public class TestCglib {

    public static void main(String[] args) {

        CgLibProxy cgLibProxy = new CgLibProxy();
        ZhouYu instance = (ZhouYu)cgLibProxy.getInstance(ZhouYu.class);

        String love = instance.findLove();
        System.out.println(love);

    }
}

二、原理

1.JDK代理原理

 测试中把内存中得代理class持久化,然后反编译来查看。

输出:

package com.vison.proxy.jdkproxy;

import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;

public class TestJdk {

    public static void main(String[] args) throws Exception {
        Person person = (Person)new JdkProxy().getInstance(new LiSi());
        person.findLove();
        System.out.println(person.getClass()); //class com.sun.proxy.$Proxy0

        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});

        FileOutputStream os = new FileOutputStream("E:\\temp\\&Proxy0.class");
        os.write(bytes);

    }
}

打开本地持久化的&Proxy0.class文件

import com.vison.proxy.jdkproxy.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m3;  //这个就是生成的方法findLove
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void findLove() throws  {
        try {
        	//这里的h就是我们实现接口 InvocationHandler的类
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.vison.proxy.jdkproxy.Person").getMethod("findLove");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

代理模式是一种结构型设计模式,它提供一个代理对象来代表另一个对象。在代理模式中,有一个被称为实际对象(Subject)和一个被称为代理对象(Proxy)的中介,代理对象持有实际对象的引用,并且可以控制对实际对象的访问。代理模式的主要目的是在不修改原始对象的情况下,为原始对象添加额外的逻辑处理。 代理模式分为多种类型,如远程代理、虚拟代理、保护代理等,它们各自有不同的应用场景: - 远程代理:为远程对象提供一个本地代表。 - 虚拟代理:根据需要创建开销大的对象,通过虚拟代理控制访问这些对象的过程。 - 保护代理:控制对原始对象的访问权限,例如进行权限检查。 代理模式的优点包括: 1. 能够控制对真实对象的访问,并在访问前后添加额外的逻辑。 2. 可以通过代理对象实现延迟加载,即在实际需要时才创建真实对象。 3. 增强了对真实对象的封装,并且可以避免对真实对象的重复引用。 在C#中实现代理模式通常涉及以下步骤: 1. 定义一个接口或抽象类,声明真实对象和代理对象需要实现的方法。 2. 实现真实对象的类,按照接口或抽象类的要求实现具体方法。 3. 实现代理类,它同样实现接口或抽象类,并在方法中持有真实对象的引用,通过调用真实对象的方法来执行所需的操作,同时可以添加额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值