代理模式(一)

1、代理模式

被代理人没有时间去做某件事情,交由代理人去做。

例子
  • 媒婆
  • 房屋中介
  • 经纪人

2、静态代理

代理模式(一)_第1张图片
image.png
  • 代理的动作接口 -- 就是要代理做的事情:相亲
public interface Person {
    public abstract void findLove();
}
  • 被代理人要实现动作接口-- 相亲要找什么样的女生
public class XiaoYuan implements Person {
    @Override
    public void findLove() {
        System.out.println("小元要找短头发、可爱的女生");
    }
}
  • 代理人实现动作接口帮助代理人 -- 在大把资源找到被代理人心仪的女生
public class MeiPo implements Person{

    private Person xiaoYuan;

    MeiPo(XiaoYuan xiaoYuan){
        this.xiaoYuan = xiaoYuan;
    }

    @Override
    public void findLove() {
        System.out.println("媒婆有大把资源,说出你想要的");
        xiaoYuan.findLove();
        System.out.println("媒婆把联系方式给你,你可以谈恋爱了");
    }

}
public class TestProxy {

    public static void main(String[] args) {
        Person meipo = new MeiPo(new XiaoYuan());
        meipo.findLove();  // 媒婆资源比较多,让媒婆帮忙找下合适的小姐姐

        // new XiaoYuan().findLove();  // 本来是要自己去找小姐姐谈恋爱的
    }
}

Output

媒婆有大把资源,说出你想要的
小元要找短头发、可爱的女生
媒婆把联系方式给你,你可以谈恋爱了

3、动态代理 (下面例子讲的是jdk的动态代理)

代理模式(一)_第2张图片
image.png
public class DynamicMeiPo implements InvocationHandler {

    private Person person;

    // 返回动态生成一个实现代理动作接口的$Proxy0.class类
    public Object newInstance(Person xiaoYuan){
        this.person = xiaoYuan;
        Class clazz = xiaoYuan.getClass();
        // 获取被代理人信息和被代理人实现的接口
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("媒婆有大把资源,说出你想要的");
        method.invoke(person,args);
        System.out.println("媒婆把联系方式给你,你可以谈恋爱了");
        return null;
    
}
  • 通过Proxy.newProxyInstance()会动态生成一个$Proxy0.class,通过下面代码会类的字节码将输出到文件。
public class TestDynamicProxy {

    public static void main(String[] args) {

        // $Proxy0.class类对象
        Person dynamicMeiPo = (Person) (new DynamicMeiPo().newInstance(new XiaoYuan()));
        dynamicMeiPo.findLove();

        // 获取$Proxy0.class类
        byte[] gengarateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{dynamicMeiPo.getClass()});
        try {
            FileOutputStream fos = new FileOutputStream("D:/$Proxy0.class" );
            fos.write(gengarateProxyClass);
            fos.close();
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
    }
}
  • 其中实现了代理要做的动作接口(Person : findLove()),$Proxy0的父类会有一个InvocationHandler h,用来接收实现InvocationHandler的DynamicMeiPo
public final class $Proxy0 extends Proxy implements Proxy0 
protected InvocationHandler h;
  • $Proxy0 这是实现Person接口的findLove()方法,当对象调用findLove(),会通过invoke(DynamicMeiPo实现的方法)
    public final void findLove() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
(1)、jdk动态代理原理
  • 1、生成代理对象类文件$Proxy0.java代码内容
    /**
     * 动态生成代理对象的代码内容
     *
     * @param interfaces
     * @return
     */
    private static String generateSrc(Class interfaces) {
        StringBuffer src = new StringBuffer();
        src.append("package com.xiaoyuan.aop.myproxy;" + LN);
        src.append("import java.lang.reflect.Method;" + LN);
        src.append("import java.lang.reflect.Proxy;" + LN);
        // 实现代理动作接口
        src.append("public final class $Proxy0 implements " + interfaces.getName() + " {" + LN);
        src.append("YInvocationHandler h;" + LN);

        src.append("public $Proxy0(YInvocationHandler h){" + LN);
        src.append("this.h = h;" + LN);
        src.append("}" + LN);
        // 代理动作接口的方法
        for (Method method : interfaces.getMethods()) {
            src.append("public final " + method.getReturnType() + " findLove()  {" + LN);
            src.append("try {" + LN);
            src.append("Method m3 = Class.forName(\"" + interfaces.getName() + "\").getMethod(\"" + method.getName() + "\");" + LN);
            src.append("h.invoke(this, m3, (Object[])null);" + LN);
            src.append("} catch (Throwable var3) {" + LN);
            src.append("System.out.println(\"出现错误\");" + LN);
            src.append("}" + LN);
            src.append("}" + LN);
        }
        src.append("}");
        return src.toString();
    }
代理模式(一)_第3张图片
image.png
  • 2、生成java文件
// 2、生成java文件
String filePath = YProxy.class.getResource("").getPath();
File f = new File(filePath + "$Proxy0.java");
FileWriter fos = new FileWriter(f);
fos.write(src);
fos.close();
  • 3、编译成生成$Proxy0.class
// 3、编译成生成$Proxy0.class
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null);
Iterable iterable = manager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null,manager,null,null,null,iterable);
task.call();
manager.close();
  • 3、$Proxy0.class加载到JVM中并返回类实例
    protected Class findClass(String name) {
        String className = YClassLoader.class.getPackage().getName() + "." + name;
        if (baseDir != null){
            // 拿到$Proxy0.class的文件位置
            File classFile = new File(baseDir, name.replaceAll("\\." , "/") + ".class");
            if (classFile.exists()){
                FileInputStream fis = null;
                try {
                    // 读取该文件到输出流out上
                    fis = new FileInputStream(classFile);
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = fis.read(buff) )!= -1){
                        out.write(buff, 0 ,len);
                    }
                    // 最后加载到jvm上
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (java.io.IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
  • 4、类实例通过反射生成实例对象返回
// 4、生成实例对象返回
Constructor c = proxyClass.getConstructor(YInvocationHandler.class);
return c.newInstance(h);
(2)、cglib动态代理原理

你可能感兴趣的:(代理模式(一))