设计模式学习笔记之(五)设计模式之代理模式

代理模式(Poxy)

概述

作用

拦截器、中介、黄牛,spring AOP,解耦,媒婆等等。

应用场景

为其他对象提供一种代理以控制对这个对象的访问。从结构上来看和 Decorator 模式类似, 但 Proxy 是控制,更像是一种对功能的限制,而 Decorator 是增加职责。
Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 和 Cglib2AopProxy。

特点

在代理角色和被代理角色之间的代理过程由被代理对象决定,而代理对象会持有被代理对象的接口或者引用(方便代理角色在完成工作之前或之后来能找到代理对象并通知被代理对象)

分类

通常代理分为静态代理和动态代理
在这里插入图片描述

静态代理

实现静态代理实例
房子接口

public interface House {
    //找房子
    public void findRoom();
    //付钱
    public void payForRoom();
    //买房子
    public void sellRoom();
}

客户类

public class Customer implements  House {
    @Override
    public void findRoom() {
        System.out.println("找房子需要又大又便宜且地段好");
    }

    @Override
    public void payForRoom() {
        System.out.println("首付少,利息少");
    }

    @Override
    public void sellRoom() {
        System.out.println("能买个好价钱");
    }
}

中介类

public class Intermediary {
    private House house;
    public Intermediary(House house){
        this.house = house;
    }

    public void  findRoom(){
        System.out.println("根据客户买房的");
        this.house.findRoom();
        System.out.println("价格便宜");
    }
}

测试类

public class StaticProxyTest1 {
    public static void main(String[] args) {
        Intermediary intermediary = new Intermediary(new Customer());
        intermediary.findRoom();
    }
}

测试结果
在这里插入图片描述

动态代理

jdk动态代理

Person 接口

public interface Person {
    public void findLove();
    public void zufangzi();
    public void buy();
    public void findJob();
    //......
}

JDKPiTiaoKe类也就是代理类

public class JDKPiTaoKe  implements InvocationHandler {
    //被代理的对象,把引用给保存下来
    private Person target;
    public Object getInstance(Person target){
        this.target =target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("这里是皮条客,专注拉皮条服务");
        System.out.println("收集客户信息,开始为客户拉皮条");
        method.invoke(target,args);
        System.out.println("安排约会,如果合适就开始办");
        return null;
    }
}

ZhaoShenYao类也就是被代理类

public class ZhaoShenYao implements Person {
    @Override
    public void findLove() {
        System.out.println("大眼睛水汪汪");
        System.out.println("大长腿");
        System.out.println("胸大,漂亮");
    }
    @Override
    public void zufangzi() {
        System.out.println("");
        System.out.println("租房子");
    }
    @Override
    public void buy() {
        System.out.println("买面包");
    }
    @Override
    public void findJob() {
        System.out.println("月薪20K-50k");
        System.out.println("找工作");
    }
}

测试类

public class JDKProxyPlay {
    public static void main(String[] args) {
       // Person instance = (Person) new JDKKuYiSou().getInstance(new ZhaoShenYao());
        Person instance = (Person) new JDKPiTaoKe().getInstance(new ZhaoShenYao());
        System.out.println(instance.getClass());
        instance.findLove();
        System.out.println("-----------------------");
        //通过反编译工具可以查看源代码
        byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
        FileOutputStream os = null;
        try {
           // os = new FileOutputStream("J://$Proxy01.class");
            os = new FileOutputStream("J://$Proxy02.class");
            os.write(bytes);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最终测试结果
在这里插入图片描述

cglib 动态代理

zhaoshengyao类被代理类

public class ZhaoShengYao {
    public void findLove(){
        System.out.println("大眼睛水汪汪");
        System.out.println("大长腿");
        System.out.println("胸大,肤白,耐看");
    }
}

CglibPiTiaoKe类即代理类

public class CglibPiTiaoKe implements MethodInterceptor {
    public Object getInstance(Class<?> clazz){
        Enhancer enhancer = new Enhancer();
        //要把哪个设置为即将生成的新类父类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return  enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("这里是皮条客,专注拉皮条服务");
        System.out.println("收集客户信息,开始为客户拉皮条");
        methodProxy.invokeSuper(o,objects);
        System.out.println("安排约会,如果合适就开始办");
        return null;
    }
}

测试类

public class CgilbProxyPlay  {
    public static void main(String[] args) {
        System.out.println("-------------");
        ZhaoShengYao instance = (ZhaoShengYao) new CglibPiTiaoKe().getInstance(ZhaoShengYao.class);
        instance.findLove();
        System.out.println(instance.getClass());
        System.out.println("-------------");
    }
}

在这里插入图片描述

静态代理和动态代理的区别

在这里插入图片描述

cglib proxy和jdk proxy之间的区别

cglib proxy

1)cglib需要实现方法拦截器。
2)cglib动态代理类和原先的类有业务继承关系,也就是父子类关系,而子类(动态代理类)会覆盖或者增强父类(被代理类)的非final修饰的方法,若果父类有final修饰的方法,则子类不能重写改动。
3)在目标对象没有实现了接口的情况下,需要采用cglib’代理,这意味着必须有CGLIB库做支撑。

jdk proxy

1)jdk依赖反射,无需第三方库。
2)jdk的代理类和被代理类则是兄弟关系,必须实现被代理类实现的接口。
3)jdk动态代理需要实现InvocationHandler接口,并重写其中的 public Object invoke(Object proxy, Method method, Object[] args)方法以便实现方法增强。

自定义动态代理类

房子接口类

public interface House {
    //找房子
    public void findRoom();
    //付钱
    public void payForRoom();
    //买房子
    public void sellRoom();
    public void rentRoom();
    public void rentalRoom();
}

shengyao接口类继承House

public class CustomerZhaoShengYao implements House {
    @Override
    public void findRoom() {
        System.out.println("赵生耀开始找房子了");
    }
    @Override
    public void payForRoom() {
        System.out.println("赵生耀开始为找到的房子付钱了");
    }

    @Override
    public void sellRoom() {
        System.out.println("赵生耀开始卖房子了");
    }

    @Override
    public void rentRoom() {
        System.out.println("赵生耀开始租房子了");
    }

    @Override
    public void rentalRoom() {
        System.out.println("赵生耀开始出租房子了");
    }
}

XSFT动态代理类

public class XSFTProxy {
    public static final String ln="\r\n";
    private static String generateSrc(Class<?> [] interfaces){
        StringBuffer sb = new StringBuffer();
        sb.append("package com.gupaoedu.vip.pattern.MyProxy;"+ln);
        sb.append("import com.gupaoedu.vip.pattern.proxy.static1.House;"+ln);
        sb.append("import java.lang.reflect.Method;"+ln);
        sb.append("public class $Proxy0 implements "+interfaces[0].getName()+"{"+ln);
        //定义变量
        sb.append("XSFTInvocationHandler h;"+ln);
        //定义构造方法
        sb.append("public $Proxy0 (XSFTInvocationHandler h)"+"{"+ln);
        sb.append("this.h = h;"+ln);
        sb.append("}"+ln);
        //写入其他方法
        for(Method m:interfaces[0].getMethods()){
            sb.append("public "+m.getReturnType().getName()+" "+m.getName()+"(){"+ln);
            sb.append("try"+"{"+ln);
            sb.append("Method m="+interfaces[0].getName()+".class.getMethod(\""+m.getName()+"\",new Class[]{});"+ln);
            sb.append("this.h.invoke(this,m,null);"+ln);
            sb.append("}catch(Exception e){"+ln);
            sb.append("e.printStackTrace();");
            sb.append("}"+ln);
            sb.append("}");
        }
        sb.append("}"+ln);
        return sb.toString();
    }
    public static Object newProxyInstance(XSFTClassloader classloader,Class<?> [] interfaces, XSFTInvocationHandler h ){
        //1、编写源代码文件后动态生成java文件
        String src = generateSrc(interfaces);
        //2、将java文件写到磁盘当中
        String filePath=XSFTProxy.class.getResource("").getPath();
        File file = new File(filePath + "$Proxy0.java");
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(file);
            fileWriter.write(src);
            fileWriter.flush();
            fileWriter.close();

            //3、把生成的.java文件编译成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> iterable = standardFileManager.getJavaFileObjects(file);
            JavaCompiler.CompilationTask task = compiler.getTask(null,standardFileManager,null,null,null,iterable);
            task.call();
            standardFileManager.close();
            //4、将编译生成的.class文件加载到jvm中
            Class<?> proxyClass = classloader.findClass("$Proxy0");
            Constructor<?> constructor = proxyClass.getConstructor(XSFTInvocationHandler.class);
            file.delete();
            //5、返回字节码重组以后的新代理对象
            return constructor.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

XSFT类加载器

public class XSFTClassloader extends ClassLoader{
    private File classPathFile;
    public XSFTClassloader(){
        String classPath = XSFTClassloader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }
    @Override
    protected Class<?> findClass(String name){
        String className=XSFTClassloader.class.getPackage().getName()+"."+name;

        if(classPathFile !=null){
            File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
            if(classFile.exists()){

                FileInputStream fileInputStream = null;
                ByteArrayOutputStream outputStream = null;
                try {
                    fileInputStream = new FileInputStream(classFile);
                    outputStream = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len=fileInputStream.read(buff))!=-1){
                        outputStream.write(buff,0,len);
                    }
                    return defineClass(className,outputStream.toByteArray(),0,outputStream.size());
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if(null != fileInputStream){
                        try {
                            fileInputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(null != outputStream ){
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

中介类

public class Intermediary implements XSFTInvocationHandler{
    private House target;
    public Object getInstance(House target){
        this.target = target;
        Class<?> clazz = target.getClass();
        return XSFTProxy.newProxyInstance(new XSFTClassloader(),clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("我是房屋中介,为客户提供租房、买卖房、以及出租房等服务");
        System.out.println("现在开始收集客户信息");
        method.invoke(this.target,args);
        System.out.println("如对价格满意, 就可以开始交易");
        return null;
    }
}

测试类

public class NomalProxyTest {
    public static void main(String[] args) {

        House instance = null;
        try {
            instance = (House) new Intermediary().getInstance(new CustomerZhaoShengYao());
            System.out.println(instance.getClass());
            instance.sellRoom();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试结果:
在这里插入图片描述
行笔至此,关于代理的相关基础知识已经学习完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值